compileall en Python: compila directorios

Publicado el: 04/08/2026
Tempo de leitura: 6 minutos
Desarrollador trabajando en automatización de build y compilación de directorios con compileall en Python

Los proyectos y paquetes Python pueden contener cientos de archivos fuente. Compilarlos individualmente con py_compile funciona, pero exige recorrer directorios, aplicar filtros y gestionar errores. El módulo compileall en Python automatiza la generación de archivos .pyc en árboles completos, con recursión, workers paralelos, niveles de optimización, exclusiones y rutas controladas para tracebacks.

Esta guía explica la interfaz de terminal y las funciones compile_dir(), compile_file() y compile_path(). Complementa nuestros artículos sobre py_compile, bytecode con dis, tokenize, tabnanny y tracebacks.

Cuándo usar compileall

Compileall resulta útil durante la instalación de bibliotecas, creación de imágenes de container, validación de sintaxis y despliegues donde los usuarios pueden leer el paquete, pero no crear __pycache__.

No convierte un proyecto en ejecutable independiente ni reemplaza los tests. La compilación solo confirma que los archivos seleccionados tienen sintaxis aceptada por el intérprete actual.

Compilar un directorio desde la terminal

python -m compileall src

El comando recorre src de forma recursiva, compila archivos .py y escribe cachés PEP 3147, normalmente dentro de __pycache__.

Compilar varias rutas

python -m compileall src tests herramientas/script.py

Los argumentos pueden ser archivos o directorios. En directorios, el recorrido es recursivo por defecto.

Ejecutar sin argumentos

Sin argumentos, la interfaz se comporta como si recibiera -l y los directorios de sys.path.

python -m compileall

Esto puede analizar mucho más código de lo esperado. La automatización debería informar raíces explícitas.

Modo no recursivo

La opción -l compila solo los archivos directamente contenidos en cada directorio.

python -m compileall -l src

Los subdirectorios se ignoran. Es útil para layouts planos o comprobaciones limitadas.

Controlar la profundidad

-r define el máximo de niveles recursivos.

python -m compileall -r 2 src

-r 0 equivale al modo no recursivo. Cuando se proporciona -r, -l no se considera.

Forzar reconstrucción

Los cachés actualizados normalmente se omiten. -f fuerza la compilación.

python -m compileall -f src

Úsalo para builds limpios, cambios de política o diagnóstico. Forzar siempre aumenta tiempo y escrituras sin beneficio cuando los artefactos están correctos.

Salida quiet

-q oculta la lista de archivos compilados, pero conserva los errores. -qq suprime toda la salida.

python -m compileall -q src

El pipeline todavía debe comprobar el status del proceso.

Paralelismo con -j

-j N utiliza workers.

python -m compileall -j 4 src

-j 0 elige una cantidad basada en os.process_cpu_count(). El paralelismo ayuda en árboles grandes, pero puede saturar CPU o almacenamiento en containers pequeños.

Varios niveles de optimización

La opción -o puede repetirse.

python -m compileall -o 0 -o 1 -o 2 src

Cada nivel genera una variante. El nivel 1 elimina asserts; el nivel 2 también elimina muchas docstrings. Usa estas variantes solo con una política clara.

Si las variantes tienen contenido idéntico, --hardlink-dupes puede consolidarlas mediante hardlinks.

python -m compileall \
  -o 0 -o 1 -o 2 \
  --hardlink-dupes \
  src

El filesystem debe soportarlos y los archivos deben estar en el mismo volumen. Las herramientas de empaquetado pueden conservar o romper la relación.

Modo de invalidación

--invalidation-mode acepta timestamp, checked-hash o unchecked-hash.

python -m compileall \
  --invalidation-mode checked-hash \
  src

Timestamp compara metadatos. Checked hash verifica contenido al importar. Unchecked hash confía en un build system externo.

SOURCE_DATE_EPOCH

Sin la variable, timestamp es el valor predeterminado. Con SOURCE_DATE_EPOCH, checked hash pasa a ser el default, ayudando a builds reproducibles.

Especificar la política explícitamente facilita auditoría y mantenimiento.

Excluir rutas con -x

-x recibe una expresión regular aplicada al camino completo.

python -m compileall \
  -x '[/\\](tests|migrations|vendor)[/\\]' \
  src

Una coincidencia omite el archivo. Prueba el patrón en Windows y Unix porque los separadores cambian.

Leer listas con -i

-i añade archivos y directorios leídos de un archivo.

python -m compileall -i rutas.txt

Usa -i - para stdin. Esto se integra con herramientas que ya seleccionaron los fuentes relevantes.

Rutas de traceback con -d

-d antepone un directorio al nombre fuente almacenado en el bytecode.

python -m compileall \
  -d /app \
  src

La ruta de build puede diferir de la desplegada. Un valor coherente hace más útiles los tracebacks posteriores.

Eliminar y añadir prefijos

-s elimina un prefijo y -p añade otro.

python -m compileall \
  -s /workspace/proyecto \
  -p /app \
  /workspace/proyecto/src

-s y -p pueden combinarse, pero no con -d. Son útiles en builds reproducibles y containers.

Limitar enlaces simbólicos

-e DIR ignora symlinks que apuntan fuera del directorio permitido.

python -m compileall -e src src

Esto reduce el recorrido fuera de la raíz. Usa igualmente una ruta controlada y permisos mínimos.

Formato legacy con -b

-b escribe .pyc junto a los archivos fuente.

python -m compileall -b src

Puede sobrescribir cachés de otra versión y pierde la convivencia que ofrece __pycache__. Úsalo solo por compatibilidad específica.

compile_dir()

La función principal recorre un árbol y devuelve verdadero solo si todos los archivos seleccionados se compilan correctamente.

import compileall

ok = compileall.compile_dir(
    "src",
    quiet=1,
)

if not ok:
    raise SystemExit("La compilación falló")

La documentación oficial de compileall describe parámetros equivalentes a las opciones de terminal.

Filtros regex

rx recibe una expresión compilada cuyo método search() procesa cada ruta completa.

import re

ok = compileall.compile_dir(
    "src",
    rx=re.compile(r"[/\\](tests|vendor)[/\\]"),
    quiet=1,
)

Un archivo omitido no se considera fallo. Registra exclusiones importantes para no saltar código de producción accidentalmente.

Workers programáticos

ok = compileall.compile_dir(
    "src",
    workers=0,
    quiet=1,
)

workers=0 usa un valor basado en CPUs. Valores negativos generan ValueError. Plataformas sin soporte pueden continuar secuencialmente.

Varios niveles en una llamada

ok = compileall.compile_dir(
    "src",
    optimize=[0, 1, 2],
    hardlink_dupes=True,
    quiet=1,
)

La secuencia crea varias variantes por fuente. Los hardlinks consolidan únicamente contenido idéntico.

compile_file()

compile_file() compila un archivo con la misma política de rutas, optimización, exclusión e invalidación.

ok = compileall.compile_file(
    "src/app.py",
    force=True,
    quiet=1,
)

Devuelve verdadero en éxito y cuando un filtro rx decide omitirlo.

compile_path()

compile_path() compila entradas de sys.path.

ok = compileall.compile_path(
    skip_curdir=True,
    quiet=1,
)

A diferencia de compile_dir(), su profundidad predeterminada es cero. Las aplicaciones rara vez necesitan compilar todo el import path.

sys.pycache_prefix

La compilación respeta sys.pycache_prefix. Los cachés solo serán útiles si el runtime usa el mismo prefijo.

Los containers pueden colocarlos en un directorio escribible separado. Mantén sincronizada la configuración entre build y ejecución.

Disponibilidad en WASI

La documentación marca compileall como no disponible en WASI. Las herramientas para WebAssembly deben detectar la plataforma.

Ejemplo de build de container

RUN python -m compileall \
    -q \
    -j 0 \
    --invalidation-mode checked-hash \
    /app

Ejecuta después de copiar dependencias y fuente. Mide si el tamaño adicional se justifica por la mejora de arranque.

Compilar no ejecuta tests

Un archivo puede compilar y todavía contener imports ausentes, errores lógicos, incompatibilidades de plataforma y fallos de tipos.

Usa compileall como etapa rápida seguida de tests, lint, type checking e inicio real de la aplicación.

Seguridad y límites

Compilar no ejecuta el cuerpo del módulo, lo cual es más seguro que importarlo. Un árbol no confiable aún puede ser enorme, contener symlinks y consumir CPU o disco.

Limita raíces, recursión, cantidad de archivos, workers y almacenamiento. No importes los cachés de código no confiable.

Errores frecuentes

  • Ejecutar sin argumentos y compilar todo sys.path.
  • Usar -b sin necesidad.
  • Escribir una regex que excluye fuente necesario.
  • Usar demasiados workers en un container pequeño.
  • Generar varios niveles sin considerar espacio.
  • Grabar rutas de despliegue incorrectas.
  • Usar unchecked hash sin un build confiable.
  • Confundir compilación con tests.

Buenas prácticas

  • Informa raíces explícitas.
  • Usa ubicaciones PEP 3147.
  • Selecciona invalidación según el build.
  • Controla workers y profundidad.
  • Prueba filtros y symlinks.
  • Graba rutas que coincidan con el despliegue.
  • Comprueba retornos o status.
  • Ejecuta tests después.

Conclusión

El módulo compileall en Python convierte la compilación de directorios completos en una etapa controlada de instalación y build. Ofrece recursión, workers paralelos, filtros, varios niveles de optimización, invalidación por hash y reescritura de rutas.

Una configuración efectiva depende del entorno: raíces explícitas, paralelismo moderado, cachés etiquetados por intérprete y política coherente. Así, compileall prepara archivos .pyc sin recorrer directorios inesperados ni confundir validación de sintaxis con calidad funcional.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Monitor con código binario que representa generación de archivos pyc con py_compile en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    py_compile en Python: genera archivos pyc

    Aprende py_compile en Python para generar archivos pyc, validar sintaxis y controlar optimización e invalidación por timestamp o hash.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Editor de código que representa corrección de tabs y espacios con tabnanny en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tabnanny en Python: corrige la indentación

    Aprende tabnanny en Python para detectar tabs y espacios ambiguos, revisar proyectos y evitar TabError e IndentationError.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Código fuente y sintaxis que representan análisis léxico con tokenize en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tokenize en Python: analiza código fuente

    Aprende tokenize en Python para analizar tokens, comentarios, encoding, posiciones y reconstruir código fuente con seguridad.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Terminal de programación que representa compilación de entradas interactivas con codeop en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    codeop en Python: compila entradas interactivas

    Aprende codeop en Python para detectar entradas completas, compilar comandos de REPL y conservar __future__ con seguridad.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Desarrollador analizando estructura de código y tablas de símbolos con symtable en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    symtable en Python: ámbitos y símbolos

    Aprende symtable en Python para analizar ámbitos, símbolos, globals, nonlocals, closures, imports, annotations y type parameters.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026
    Monitor con código binario que representa análisis de bytecode con dis en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    dis en Python: entiende el bytecode

    Aprende dis en Python para analizar bytecode, instrucciones, cachés adaptativas, posiciones, tracebacks y detalles internos de CPython.

    Ler mais

    Tempo de leitura: 7 minutos
    03/08/2026