Projetos e pacotes Python podem conter centenas de arquivos-fonte. Compilá-los individualmente com py_compile funciona, mas exige percorrer diretórios, aplicar filtros e gerenciar falhas. O módulo compileall no Python automatiza a geração de arquivos .pyc em árvores inteiras, com recursão, paralelismo, níveis de otimização, exclusões e caminhos adequados para tracebacks.
Neste guia, você aprenderá a usar a interface de linha de comando e as funções compile_dir(), compile_file() e compile_path(). O conteúdo complementa nossos artigos sobre py_compile, bytecode com dis, tokenize, tabnanny e tracebacks.
Quando usar compileall
Compileall é útil em instalação de bibliotecas, criação de imagens de container, validação de sintaxe em builds e ambientes onde os usuários podem ler o pacote, mas não possuem permissão para criar __pycache__.
Ele não transforma o projeto em um executável nem substitui testes. A compilação comprova que cada arquivo analisado possui sintaxe compatível com o interpretador atual.
Compilar um diretório pela terminal
python -m compileall srcO comando percorre src recursivamente, compila arquivos .py e grava caches nos caminhos PEP 3147, normalmente dentro de __pycache__.
Compilar vários caminhos
python -m compileall src tests ferramentas/script.pyArgumentos posicionais podem ser arquivos ou diretórios. Em diretórios, a busca é recursiva por padrão.
Execução sem argumentos
Sem argumentos, a interface se comporta como se recebesse -l e os diretórios de sys.path.
python -m compileallEsse comportamento pode percorrer muito mais código que o esperado. Em automação, informe explicitamente as raízes do projeto.
Não recursivo com -l
A opção -l compila apenas arquivos diretamente no diretório informado.
python -m compileall -l srcSubdiretórios não são visitados. A opção é útil para diretórios planos ou para uma primeira etapa controlada.
Controlar profundidade
-r define o máximo de níveis recursivos.
python -m compileall -r 2 src-r 0 equivale ao comportamento não recursivo. Quando -r é informado, -l deixa de ser considerado.
Forçar recompilação
Normalmente caches atualizados são ignorados. -f força a reconstrução.
python -m compileall -f srcUse em builds limpos, mudanças de política de invalidação ou diagnóstico. Forçar sempre aumenta tempo e gravações sem benefício quando os artefatos já estão corretos.
Saída quiet
-q omite a lista de arquivos compilados, mas mantém erros. -qq suprime toda a saída.
python -m compileall -q srcMesmo sem mensagens, o pipeline deve verificar o código de saída.
Paralelismo com -j
-j N usa workers para compilar arquivos em paralelo.
python -m compileall -j 4 srcCom -j 0, o número é escolhido a partir de os.process_cpu_count(). O paralelismo ajuda em árvores grandes, mas pode saturar CPU e armazenamento em containers pequenos.
Múltiplos níveis de otimização
A opção -o pode ser repetida.
python -m compileall -o 0 -o 1 -o 2 srcCada nível gera uma variante de cache. O nível 1 remove asserts; o nível 2 também remove muitas docstrings. Não use otimização sem entender essas alterações.
Consolidar duplicatas com hardlinks
Quando variantes de otimização possuem conteúdo idêntico, --hardlink-dupes pode usar hardlinks.
python -m compileall \
-o 0 -o 1 -o 2 \
--hardlink-dupes \
srcO filesystem precisa oferecer hardlinks e os arquivos devem permanecer no mesmo volume. Ferramentas de empacotamento e cópia podem desfazer ou preservar a relação de maneiras diferentes.
Modo de invalidação
--invalidation-mode aceita timestamp, checked-hash ou unchecked-hash.
python -m compileall \
--invalidation-mode checked-hash \
srcTimestamp compara metadados. Hash verificado compara o conteúdo ao importar. Hash não verificado confia em um sistema externo para manter os caches atualizados.
SOURCE_DATE_EPOCH
Sem a variável, o padrão é timestamp. Com SOURCE_DATE_EPOCH, o padrão passa a hash verificado, ajudando builds reproduzíveis.
Em pipelines determinísticos, informe também a política explicitamente para tornar a intenção visível.
Filtrar caminhos com -x
-x recebe uma expressão regular aplicada ao caminho completo.
python -m compileall \
-x '[/\\](tests|migrations|vendor)[/\\]' \
srcSe a regex encontrar correspondência, o arquivo é ignorado. Teste o padrão em Windows e Unix, pois separadores diferem.
Ler uma lista com -i
-i adiciona arquivos e diretórios lidos de um arquivo.
python -m compileall -i caminhos.txtUse -i - para ler de stdin. Essa opção facilita integração com ferramentas que já selecionaram os arquivos.
Caminhos em tracebacks com -d
-d prefixa o caminho registrado dentro do bytecode.
python -m compileall \
-d /app \
srcO caminho de build pode ser diferente do caminho de implantação. Um valor coerente torna tracebacks posteriores mais úteis.
Remover e adicionar prefixos
-s remove um prefixo dos caminhos e -p adiciona outro.
python -m compileall \
-s /workspace/projeto \
-p /app \
/workspace/projeto/src-s e -p podem ser usados juntos, mas não com -d. Isso é útil em builds reproduzíveis e containers.
Limitar links simbólicos
-e DIR ignora symlinks que apontam para fora do diretório permitido.
python -m compileall -e src srcEssa proteção reduz a chance de sair da raiz por um link. Ainda assim, escolha uma raiz controlada e execute com permissões mínimas.
Formato legacy com -b
-b grava .pyc ao lado do arquivo-fonte, no formato legado.
python -m compileall -b srcEsse modo pode sobrescrever caches criados por outra versão e elimina a convivência fornecida por __pycache__. Use apenas por compatibilidade específica.
compile_dir()
A função programática principal percorre uma árvore e retorna True se todos os arquivos forem compilados.
import compileall
ok = compileall.compile_dir(
"src",
quiet=1,
)
if not ok:
raise SystemExit("Falha ao compilar")A documentação oficial de compileall descreve opções equivalentes à CLI.
Filtros com expressão regular
rx recebe um objeto compilado e usa seu método search().
import re
ok = compileall.compile_dir(
"src",
rx=re.compile(r"[/\\](tests|vendor)[/\\]"),
quiet=1,
)Um arquivo ignorado não é falha. Registre exclusões importantes para evitar omitir código de produção por engano.
Paralelismo programático
ok = compileall.compile_dir(
"src",
workers=0,
quiet=1,
)workers=0 usa a quantidade de CPUs. Valores negativos geram ValueError. Se a plataforma não suportar múltiplos workers, a função pode continuar sequencialmente.
Vários níveis em uma chamada
ok = compileall.compile_dir(
"src",
optimize=[0, 1, 2],
hardlink_dupes=True,
quiet=1,
)A sequência produz várias variantes por fonte. Hardlinks só consolidam arquivos de conteúdo igual.
compile_file()
compile_file() compila um único arquivo com a mesma política de caminhos, otimização e invalidação.
ok = compileall.compile_file(
"src/app.py",
force=True,
quiet=1,
)Ela devolve verdadeiro em sucesso e também quando um filtro rx decide ignorar o arquivo.
compile_path()
compile_path() percorre entradas de sys.path.
ok = compileall.compile_path(
skip_curdir=True,
quiet=1,
)Diferentemente de compile_dir(), o limite de profundidade padrão é zero. Em aplicações, compilar todo o sys.path raramente é necessário.
sys.pycache_prefix
A compilação respeita sys.pycache_prefix. O cache gerado será útil somente se o runtime utilizar o mesmo prefixo.
Containers podem direcionar caches para um diretório gravável separado. Documente a configuração entre build e execução.
Indisponibilidade em WASI
A documentação marca compileall como indisponível em WASI. Ferramentas destinadas a WebAssembly precisam detectar a plataforma e não presumir que a API existe ou funciona.
Pipeline de container
RUN python -m compileall \
-q \
-j 0 \
--invalidation-mode checked-hash \
/appExecute após copiar dependências e código. Avalie se os caches aumentam a imagem mais do que reduzem o tempo de inicialização.
Compilação não executa testes
Um arquivo pode compilar e ainda conter imports ausentes, erros de lógica, incompatibilidades de plataforma e falhas de tipo.
Use compileall como etapa rápida, seguida de testes, lint, type checking e inicialização real do pacote.
Segurança
Compilar não executa o corpo dos módulos, o que é mais seguro que importá-los. Porém, árvores não confiáveis podem ser enormes, conter symlinks e consumir CPU ou armazenamento.
Limite raiz, profundidade, quantidade de arquivos, workers e espaço disponível. Não importe os caches produzidos por código não confiável.
Erros frequentes
- Executar sem argumentos e compilar todo o sys.path.
- Usar
-bsem necessidade. - Aplicar regex que exclui arquivos importantes.
- Usar workers ilimitados em container pequeno.
- Gerar vários níveis sem considerar espaço.
- Configurar caminhos de traceback incorretos.
- Usar unchecked-hash sem build confiável.
- Confundir compilação com testes.
Boas práticas
- Informe raízes explicitamente.
- Use caches PEP 3147.
- Escolha invalidação conforme o build.
- Controle workers e profundidade.
- Teste filtros e symlinks.
- Use caminhos de traceback iguais ao ambiente final.
- Verifique o valor retornado ou código de saída.
- Execute testes após a compilação.
Conclusão
O módulo compileall no Python transforma a compilação de árvores inteiras em uma etapa controlável de instalação e build. Ele oferece recursão, paralelismo, filtros, múltiplos níveis de otimização, invalidação por hash e ajuste dos caminhos gravados no bytecode.
Uma configuração eficiente depende do ambiente: raízes explícitas, workers moderados, caches versionados pelo interpretador e política de invalidação coerente. Assim, compileall prepara arquivos .pyc sem atravessar diretórios indevidos nem confundir validação sintática com qualidade funcional.







