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

    Código y compilador que representan rutas y variables de build con sysconfig en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sysconfig en Python: rutas y build

    Aprende sysconfig en Python para descubrir rutas de instalación, variables de build, headers, virtualenvs y plataformas de forma segura.

    Ler mais

    Tempo de leitura: 6 minutos
    09/08/2026
    Disco duro que representa archivos mapeados en memoria con mmap en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    mmap en Python: archivos en memoria

    Aprende mmap en Python para mapear archivos en memoria, buscar bytes, compartir datos y elegir lectura, escritura o copy-on-write.

    Ler mais

    Tempo de leitura: 6 minutos
    09/08/2026
    Código fuente que representa tokens y constantes del parser con el módulo token en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    token en Python: constantes del parser

    Aprende token en Python para interpretar tipos léxicos, operadores exactos, indentación, f-strings, t-strings y parsers por versión.

    Ler mais

    Tempo de leitura: 7 minutos
    07/08/2026
    Código fuente que representa palabras reservadas y soft keywords en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    keyword en Python: palabras reservadas

    Aprende keyword en Python para validar identificadores, palabras reservadas y soft keywords según la versión del intérprete.

    Ler mais

    Tempo de leitura: 7 minutos
    07/08/2026
    Arquitectura de software que representa clases abstractas con abc en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    abc en Python: clases abstractas

    Aprende abc en Python para crear clases abstractas, métodos obligatorios, subclasses virtuales y contratos estables.

    Ler mais

    Tempo de leitura: 5 minutos
    06/08/2026
    Código y estructuras que representan tipos del runtime con el módulo types en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    types en Python: tipos del runtime

    Aprende types en Python para usar SimpleNamespace, MappingProxyType, tipos del runtime y creación dinámica de clases.

    Ler mais

    Tempo de leitura: 5 minutos
    06/08/2026