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

    Detailed view of programming code in a dark theme on a computer screen.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    linecache no Python: leia linhas do código

    Aprenda linecache no Python para recuperar linhas de código, atualizar cache, integrar tracebacks, lidar com loaders e proteger caminhos.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    faulthandler no Python: diagnostique crashes

    Aprenda faulthandler no Python para diagnosticar crashes, deadlocks, timeouts, sinais fatais e travamentos com dumps de todas as threads.

    Ler mais

    Tempo de leitura: 10 minutos
    27/08/2026
    A close-up of a coin-operated telescope set against a beautiful cloudy sky, ideal for travel imagery.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    symtable no Python: analise escopos

    Aprenda symtable no Python para analisar escopos, locals, globals, parâmetros, imports, nonlocals, closures e namespaces usados pelo compilador.

    Ler mais

    Tempo de leitura: 9 minutos
    27/08/2026
    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    dis no Python: entenda o bytecode

    Aprenda dis no Python para desmontar bytecode, analisar instruções, jumps, pilha, caches adaptativos e otimizações sem depender de internals instáveis.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026
    Flat lay of gold bitcoin coins on a pink surface, symbolizing cryptocurrency and modern investment.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tokenize no Python: leia tokens do código

    Aprenda tokenize no Python para ler tokens, comentários, encoding, indentação e posições, além de transformar e reconstruir código com segurança.

    Ler mais

    Tempo de leitura: 7 minutos
    27/08/2026
    Color-coded office binders organized neatly in a storage shelf, featuring labels and a striking red binder.
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    zipapp no Python: crie arquivos .pyz

    Aprenda zipapp no Python para criar arquivos .pyz, definir entry points, incluir dependências, usar recursos e distribuir CLIs com segurança.

    Ler mais

    Tempo de leitura: 8 minutos
    27/08/2026