codeop no Python: compile comandos interativos

Publicado em: 27/08/2026
Tempo de leitura: 8 minutos
A classic MS-DOS terminal screen displayed on a laptop keyboard with vivid illumination.

O módulo codeop ajuda a compilar trechos de Python recebidos de forma interativa. Seu principal diferencial é distinguir três situações: código completo e válido, código inválido e código que ainda está incompleto, mas pode se tornar válido quando o usuário digitar mais linhas. Essa capacidade é essencial em REPLs, consoles embutidos, notebooks, shells administrativos, editores educacionais e ferramentas que executam comandos multilinha.

Uma chamada comum a compile() não foi projetada para decidir se um bloco precisa apenas de mais entrada. O módulo codeop encapsula heurísticas compatíveis com o console do Python e também mantém o efeito de declarações from __future__ entre comandos quando usamos CommandCompiler.

O problema do código incompleto

Considere uma função digitada linha por linha:

def dobro(valor):
    return valor * 2

Depois da primeira linha, o código não deve ser rejeitado; o console deve pedir a continuação. Depois do corpo e de uma linha que finalize a entrada, ele pode compilar e executar.

compile_command

A função compile_command(source, filename="<input>", symbol="single") tenta decidir o estado do trecho.

import codeop

resultado = codeop.compile_command("1 + 2")
print(resultado)

Quando o código está completo, o retorno é um code object. Quando parece incompleto, o retorno é None. Quando está definitivamente inválido, uma exceção de sintaxe é lançada.

Três resultados possíveis

Uma aplicação deve tratar os três estados explicitamente:

def analisar(entrada):
    try:
        codigo = codeop.compile_command(entrada)
    except (SyntaxError, OverflowError, ValueError) as erro:
        return "invalido", erro

    if codigo is None:
        return "incompleto", None
    return "completo", codigo

Não transforme None em erro. Ele é o sinal de que a interface deve continuar coletando linhas.

O parâmetro symbol

O argumento symbol controla o tipo de entrada esperado. Os valores comuns são single, exec e eval.

  • single representa uma instrução interativa e pode produzir exibição automática de expressões.
  • exec representa um conjunto de instruções.
  • eval aceita uma expressão.
expressao = codeop.compile_command(
    "10 * 4",
    filename="<calculadora>",
    symbol="eval",
)

Escolha o modo correto

Um console tradicional costuma usar single. Um editor que executa células com várias instruções pode usar exec. Uma calculadora restrita pode usar eval, embora executar expressões não confiáveis continue sendo perigoso.

O modo não cria segurança; ele apenas define a gramática e o tipo de code object.

Acumule linhas

Um REPL simples mantém um buffer até que a entrada fique completa.

import codeop

linhas = []
while True:
    prompt = "... " if linhas else ">>> "
    linha = input(prompt)
    linhas.append(linha)
    fonte = "\n".join(linhas)

    try:
        codigo = codeop.compile_command(fonte)
    except SyntaxError as erro:
        print(f"erro: {erro}")
        linhas.clear()
        continue

    if codigo is None:
        continue

    exec(codigo, namespace)
    linhas.clear()

Um console real também precisa tratar EOF, KeyboardInterrupt, histórico, encoding e exceções de execução.

Linhas em branco

Consoles usam linhas em branco para concluir alguns blocos compostos. A interface deve preservar essa semântica em vez de remover toda entrada vazia.

Não aplique strip() ao buffer completo, pois isso pode alterar indentação e finalização.

Indentação

Espaços iniciais são parte da sintaxe. Ao acumular linhas, preserve exatamente o texto digitado.

Uma interface pode exibir dicas de indentação, mas não deve reformatar silenciosamente o código antes de compilar.

SyntaxError

Código definitivamente inválido gera SyntaxError.

try:
    codeop.compile_command("if :")
except SyntaxError as erro:
    print(erro.msg, erro.lineno, erro.offset)

Mostre filename, linha, coluna e trecho sem expor buffers de outros usuários.

Outras exceções de compilação

Entradas extremas podem produzir OverflowError, ValueError ou outras falhas associadas à compilação. Defina limites de tamanho, profundidade e tempo antes de chamar o compilador em um serviço público.

Não aumente o limite de recursão como resposta automática a uma entrada hostil.

Filename simbólico

O parâmetro filename aparece em tracebacks e diagnósticos.

codigo = codeop.compile_command(
    fonte,
    filename="<console-admin>",
)

Use um nome que identifique a sessão sem revelar dados pessoais. Para células, inclua um ID estável que permita recuperar o conteúdo correspondente.

Integração com linecache

Code objects gerados dinamicamente não possuem um arquivo real. Se você quiser que tracebacks mostrem a linha correta, mantenha um armazenamento de fonte associado ao filename e integre-o cuidadosamente ao mecanismo de cache.

Veja linecache no Python para recuperação de linhas.

CommandCompiler

A classe CommandCompiler funciona como uma versão stateful de compile_command().

import codeop

compilador = codeop.CommandCompiler()
codigo = compilador("x = 10")

Ela é importante quando comandos sucessivos pertencem à mesma sessão interativa.

Declarações from __future__

Em um módulo, uma declaração from __future__ import ... afeta o restante do arquivo. Em um console, ela deve afetar comandos posteriores da sessão.

CommandCompiler lembra as flags futuras observadas em compilações anteriores, aproximando o comportamento do interpretador interativo.

compilador = codeop.CommandCompiler()
compilador("from __future__ import annotations")
proximo = compilador("def f(x: Tipo) -> Outro: pass")

Um compilador por sessão

Não compartilhe uma única instância de CommandCompiler entre usuários independentes. Flags futuras e estado de sessão poderiam vazar de um contexto para outro.

Crie uma instância por console, notebook, conexão ou tenant.

Compile versus execute

Compilar verifica sintaxe e cria bytecode; não executa o corpo. A execução ocorre com exec() ou eval().

Mesmo a compilação pode consumir recursos, mas o risco principal surge na execução, que permite imports, arquivos, rede, subprocessos e introspecção.

Não é sandbox

codeop não restringe o código. Um modo eval, uma lista de builtins reduzida ou uma inspeção superficial de AST não transforma Python em uma linguagem segura.

Para código não confiável, use isolamento forte: processo separado, usuário sem privilégios, filesystem restrito, limites de CPU e memória, rede controlada e tempo máximo.

Namespaces

Um console costuma manter um dicionário de globals entre comandos.

namespace = {"__name__": "__console__"}
exec(codigo, namespace, namespace)

Isso permite que variáveis e funções persistam. Também significa que memória e recursos podem acumular durante a sessão.

Separe sessões

Cada usuário deve possuir seu próprio namespace. Compartilhar globals permite leitura e alteração de dados de outras sessões.

Destrua o processo ou namespace ao encerrar, mas lembre que objetos nativos e threads iniciadas pelo código podem sobreviver se o isolamento for fraco.

Exibição de expressões

O modo single integra-se ao mecanismo de display do interpretador para expressões. Em consoles personalizados, configure sys.displayhook com cuidado se quiser controlar representação e histórico.

Use reprlib para limitar objetos gigantes. Veja reprlib no Python.

Resultados grandes

Uma expressão pode produzir uma representação enorme ou recursiva. Limite tamanho de saída, linhas e tempo de serialização.

Não faça repr() de objetos controlados por código hostil no processo principal; métodos especiais podem executar lógica arbitrária.

Captura de stdout e stderr

Consoles web normalmente capturam saída. contextlib.redirect_stdout() altera estado global e não é seguro para várias sessões concorrentes no mesmo processo.

Isolar cada sessão em processo simplifica streams, sinais, limites e encerramento.

Exceções de execução

Depois da compilação, envolva a execução em um bloco que capture BaseException apenas no boundary correto, sem engolir sinais de shutdown por acidente.

try:
    exec(codigo, namespace, namespace)
except SystemExit:
    encerrar_sessao()
except Exception:
    traceback.print_exc()

Defina uma política explícita para KeyboardInterrupt, GeneratorExit e SystemExit.

Timeout de execução

Uma thread não consegue interromper com segurança qualquer código Python ou nativo. Use processos descartáveis e finalize o worker quando o prazo expirar.

Antes de matar, um dump com faulthandler pode ajudar no diagnóstico de sessões internas confiáveis.

Async e await

Um console assíncrono pode querer suportar await no nível superior. Isso exige flags de compilação e um event loop apropriado; codeop básico não fornece sozinho uma política completa de top-level await.

Use APIs do compilador e do framework interativo compatíveis com a versão do Python.

Notebooks

Notebooks mantêm uma sessão, histórico, IDs de células, display protocol, execução assíncrona e armazenamento de fonte. codeop resolve apenas a decisão sintática de completude e flags futuras.

Não tente recriar um kernel completo apenas com um loop de input().

Consoles administrativos

Um console dentro de um serviço é uma superfície de alto risco. Proteja com autenticação forte, autorização, auditoria, rede privada e acesso temporário.

Prefira comandos administrativos declarativos a execução arbitrária de Python.

Histórico

Se armazenar comandos, criptografe e defina retenção. Entradas podem conter tokens, dados pessoais e segredos digitados acidentalmente.

Permita apagar o histórico e não registre automaticamente conteúdo de sessões sensíveis.

Limites de entrada

Defina máximo de bytes, linhas, tempo esperando continuação e nesting. Um cliente pode enviar um bloco incompleto indefinidamente para ocupar recursos.

Após o timeout, descarte o buffer e encerre a sessão ou solicite nova entrada.

Cancelamento do buffer

Ofereça um comando para limpar o trecho atual sem destruir todo o namespace.

if linha == ":cancelar":
    linhas.clear()
    continue

Use comandos fora da sintaxe Python e documente conflitos.

Autocomplete

A decisão de completude não fornece autocomplete. Para sugestões, use análise de tokens, AST parcial, symbol tables ou um language server.

Evite executar propriedades e descriptors apenas para descobrir atributos; isso pode gerar side effects.

Versionamento

A gramática e as heurísticas de código incompleto evoluem com o Python. Teste seu console em cada versão suportada.

Não copie implementações internas antigas; use o módulo da própria versão em execução.

Testes

Inclua expressões simples, funções multilinha, classes, decorators, parênteses abertos, strings triplas, comprehensions, try/except, match, async, erros definitivos, EOF, interrupção e declarações futuras.

Teste também que sessões independentes não compartilham namespace nem flags.

Erros comuns

Os erros mais frequentes são tratar None como falha, remover indentação, usar o modo errado, compartilhar CommandCompiler, executar código não confiável no processo principal, capturar streams globalmente, não limitar buffers e confundir compilação com sandbox.

Conclusão

codeop fornece a lógica necessária para saber se uma entrada interativa está completa, incompleta ou inválida. Use compile_command() em casos stateless e CommandCompiler para sessões que precisam preservar flags de __future__.

Separe namespaces, preserve a fonte para tracebacks, limite recursos e isole a execução. Consulte a documentação oficial de codeop e o guia de symtable no Python para analisar nomes de uma sessão.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Código de programação Python em uma tela
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    T-strings e templatelib: interpolação estruturada

    Aprenda t-strings e string.templatelib no Python para processar interpolações, criar renderizadores seguros e preservar dados estruturados.

    Ler mais

    Tempo de leitura: 6 minutos
    22/10/2026
    Banco SQLite e código Python para exportação seletiva com iterdump
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    SQLite iterdump: crie dumps seletivos no Python

    Aprenda sqlite3.Connection.iterdump com filtro para gerar dumps seletivos, validar dependências e restaurar bancos com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    21/10/2026
    Código e arquivos representando compressão de dados no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    compression.zstd: Zstandard rápido no Python

    Aprenda a usar compression.zstd no Python para comprimir e descomprimir dados com desempenho, streaming e segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    21/10/2026
    Arquivo de configuração e estrutura de código para ConfigParser no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    ConfigParser: leia INI sem seção no Python

    Aprenda a ler arquivos INI sem cabeçalho usando ConfigParser, com validação, tipos, compatibilidade e escrita segura.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026
    Dados binários e memória de computador representando memoryview no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    memoryview count e index: busque sem copiar

    Aprenda memoryview count e index no Python para buscar valores em buffers sem cópias e validar dados binários com eficiência.

    Ler mais

    Tempo de leitura: 5 minutos
    20/10/2026
    Desenvolvedora trabalhando com código Python e validação de dados
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    map strict: detecte iteráveis desalinhados

    Aprenda map strict no Python para validar iteráveis, evitar truncamento silencioso e detectar dados desalinhados.

    Ler mais

    Tempo de leitura: 6 minutos
    19/10/2026