O módulo py_compile compila um arquivo-fonte Python individual para bytecode .pyc. Ele é a camada direta usada quando uma ferramenta precisa validar ou preparar um arquivo específico, escolher o caminho de saída, controlar o filename exibido em tracebacks, definir otimização e selecionar a política de invalidação do cache.
Para compilar árvores inteiras, compileall é mais conveniente. Para um editor, pipeline incremental, gerador de código, instalador ou teste que trabalha arquivo por arquivo, py_compile oferece controle mais preciso.
A função compile
A API principal é py_compile.compile().
import py_compile
caminho_pyc = py_compile.compile(
"modulo.py",
doraise=True,
)
print(caminho_pyc)
Quando a compilação é bem-sucedida, o retorno indica o caminho do arquivo gerado.
doraise
Com doraise=True, erros de compilação são lançados como PyCompileError.
try:
py_compile.compile("modulo.py", doraise=True)
except py_compile.PyCompileError as erro:
print(erro)
Em automação, prefira essa opção para que o caller possa interromper o build e registrar um diagnóstico estruturado.
Comportamento sem doraise
Quando doraise=False, a função pode escrever a mensagem em stderr e retornar um resultado que indica falha. Esse comportamento é útil em uso interativo, mas menos claro em pipelines.
Não ignore o retorno. Um arquivo de saída antigo pode continuar no disco e dar a falsa impressão de sucesso.
PyCompileError
A exceção encapsula informações sobre o erro, incluindo a exceção original e uma mensagem formatada.
Preserve filename, linha, coluna e tipo. Em uma interface, mostre um trecho curto usando linecache no Python.
Destino padrão
Sem cfile, o módulo calcula o caminho padrão em __pycache__, seguindo a convenção do sistema de importação.
__pycache__/modulo.cpython-314.pycO nome inclui uma tag do interpretador e, quando necessário, o nível de otimização.
Escolha cfile
O parâmetro cfile define explicitamente o arquivo de saída.
py_compile.compile(
"src/modulo.py",
cfile="build/modulo.pyc",
doraise=True,
)
Crie o diretório pai e valide o destino antes de compilar.
Evite sobrescrever caminhos perigosos
O módulo possui proteções contra alguns destinos que seriam substituídos de forma insegura, como links simbólicos ou arquivos não regulares em situações relevantes.
Ainda assim, não aceite cfile controlado por usuário. Restrinja a uma raiz de build e resolva o path.
Escrita atômica
A implementação moderna grava o bytecode de forma temporária e substitui o destino, reduzindo o risco de um cache parcialmente escrito.
Atomicidade depende das garantias do filesystem. Em volumes de rede, mounts especiais e falhas de disco, teste o comportamento real.
O parâmetro dfile
dfile define o filename lógico armazenado no code object e exibido em tracebacks.
py_compile.compile(
"/build/work/modulo.py",
dfile="/opt/app/modulo.py",
doraise=True,
)
Isso é importante quando o path da máquina de build não existe no servidor final.
dfile não move o fonte
O parâmetro altera apenas a referência lógica. Ele não copia arquivos nem garante que o path exista em runtime.
Alinhe dfile ao layout real e preserve source maps ou artefatos de depuração quando o código-fonte não for instalado.
Otimização
O parâmetro optimize seleciona o nível de otimização.
py_compile.compile(
"modulo.py",
optimize=1,
doraise=True,
)
O valor padrão usa a configuração atual do interpretador.
Assert e docstrings
Otimização nível 1 remove asserts; nível 2 também pode remover docstrings.
Não use asserts para validação de segurança, entrada externa ou regras de negócio obrigatórias.
Política de invalidação
invalidation_mode controla como o importador decide se um .pyc ainda corresponde ao fonte.
py_compile.compile(
"modulo.py",
doraise=True,
invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH,
)
TIMESTAMP
No modo TIMESTAMP, o cache registra metadados como hora de modificação e tamanho.
É eficiente e tradicional, mas pode ser menos adequado a builds reproduzíveis e filesystems com timestamps inconsistentes.
CHECKED_HASH
O modo CHECKED_HASH armazena um hash do fonte e solicita verificação durante a importação.
Ele oferece uma relação mais forte entre conteúdo e bytecode, com custo adicional de leitura e hash conforme a política do importador.
UNCHECKED_HASH
UNCHECKED_HASH grava o hash, mas permite que o ambiente trate o arquivo como pré-validado e não confira o fonte em cada importação.
Use somente em um sistema de build confiável que controla instalação e atualização do artefato.
SOURCE_DATE_EPOCH
Ambientes reproducíveis podem definir SOURCE_DATE_EPOCH, influenciando o modo padrão escolhido.
Defina explicitamente invalidation_mode quando a política fizer parte do contrato do build.
Compile sem executar
A função analisa e gera bytecode, mas não executa o corpo do módulo.
Imports ausentes, erros em decorators, chamadas de nível superior e falhas nativas só aparecem quando o módulo é importado ou executado.
Validação incremental
Um editor pode compilar apenas o arquivo salvo.
def validar(caminho):
try:
py_compile.compile(caminho, doraise=True)
except py_compile.PyCompileError as erro:
return False, str(erro)
return True, None
Isso detecta sintaxe rapidamente, mas não substitui um language server ou type checker.
Arquivos gerados
Geradores podem compilar imediatamente a saída para garantir que templates produziram Python válido.
Grave o fonte de forma atômica, compile e só então publique o artefato. Se a compilação falhar, preserve o arquivo em uma área de diagnóstico protegida.
Encoding
O compilador respeita regras de encoding de fonte Python. Um arquivo com declaração inválida ou bytes incompatíveis pode falhar.
Use tokenize.open() para inspeção prévia e leia o guia de tokenize no Python.
Filename e privacidade
Paths absolutos armazenados no code object podem revelar nomes de usuários, diretórios de CI e estrutura interna.
Use dfile para produzir tracebacks úteis e neutros, sem esconder informação necessária à equipe.
CLI
O módulo pode ser executado pela linha de comando para compilar arquivos.
python -m py_compile modulo.py outro.pyUse o exit code no CI. A interface disponível pode evoluir, então consulte a ajuda da versão usada.
Vários arquivos
A CLI aceita vários paths, mas a API de compile() trabalha um por vez. Para uma árvore, prefira compileall no Python.
Em processamento incremental, mantenha uma fila limitada e associe cada resultado ao arquivo.
Concorrência
Arquivos independentes podem ser compilados em paralelo, mas evite dois workers escrevendo o mesmo cfile.
Use destinos determinísticos e deduplique tarefas antes de iniciar.
Race conditions
O fonte pode mudar entre leitura, compilação e publicação. Em um editor, isso pode gerar bytecode de uma versão que já não é a atual.
Compare hash ou versão do documento antes de aceitar o resultado.
Diretórios read-only
Se o destino padrão não puder ser criado, escolha uma área de build com permissão ou compile durante a criação da imagem.
Não execute como root apenas para escrever __pycache__.
Bytecode não é portável entre versões
Compile com o mesmo Python major/minor e implementação do runtime. O magic number do arquivo protege contra muitos usos incompatíveis.
Não armazene um .pyc como artefato universal.
Bytecode não é ofuscação
Ferramentas podem extrair nomes, constantes e instruções. .pyc não deve conter segredos e não oferece proteção robusta de propriedade intelectual.
Teste importação
Depois da compilação, execute um smoke test no ambiente de destino.
python -c "import modulo"Isso detecta dependências e inicialização que a compilação não cobre.
Arquivos órfãos
Se o fonte for removido, caches antigos podem permanecer. A forma como serão importados depende do layout e do mecanismo usado.
O pipeline deve limpar artefatos antes de construir, evitando que módulos removidos sobrevivam no pacote.
Build limpo
Crie o diretório de saída do zero ou use uma limpeza validada. Não misture caches de commits e versões diferentes.
Artefatos antigos são uma causa comum de comportamento impossível de reproduzir.
Segurança de paths
Valide file, cfile e diretórios pai. Não siga symlinks não confiáveis e não escreva fora do workspace.
Em um serviço, compile dentro de um sandbox de filesystem e processo.
DoS de compilação
Entradas muito grandes ou profundamente aninhadas podem consumir recursos. Limite tamanho, tempo e quantidade de jobs.
Não compile uploads hostis no processo web principal.
Observabilidade
Registre arquivo lógico, duração, tamanho, versão do Python, otimização e modo de invalidação. Não registre todo o fonte.
Métricas de falhas por gerador ou pacote ajudam a identificar regressões.
Testes
Inclua arquivo válido, SyntaxError, encoding inválido, destino customizado, dfile, cada modo de invalidação, otimização, diretório sem permissão, link simbólico e fonte alterado durante a tarefa.
Verifique também o filename mostrado no traceback.
Erros comuns
Os erros frequentes são omitir doraise=True no CI, ignorar o retorno, sobrescrever um destino perigoso, compilar com versão diferente, usar asserts como validação, confundir dfile com cópia, deixar caches órfãos e acreditar que bytecode protege o código.
Conclusão
py_compile oferece controle direto sobre a compilação de um arquivo Python. Use doraise=True, escolha cfile e dfile com segurança, defina otimização e invalidação conforme o build e valide a importação no ambiente final.
Para árvores completas, use compileall. Consulte a documentação oficial de py_compile e o artigo de dis no Python para inspecionar o bytecode produzido.







