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 srcEl 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.pyLos 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 compileallEsto 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 srcLos 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 srcEl 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 srcCada 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.
Consolidar duplicados con hardlinks
Si las variantes tienen contenido idéntico, --hardlink-dupes puede consolidarlas mediante hardlinks.
python -m compileall \
-o 0 -o 1 -o 2 \
--hardlink-dupes \
srcEl 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 \
srcTimestamp 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)[/\\]' \
srcUna 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.txtUsa -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 \
srcLa 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 srcEsto 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 srcPuede 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 \
/appEjecuta 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
-bsin 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.







