O módulo code no Python oferece as classes usadas para construir loops de leitura, avaliação e exibição, conhecidos como REPLs. Com InteractiveInterpreter e InteractiveConsole, uma aplicação pode fornecer um prompt Python embutido, controlar o namespace, capturar mensagens de erro e decidir como linhas incompletas serão acumuladas.
Esse recurso é valioso em ferramentas de ensino, depuradores, notebooks simplificados, consoles administrativos e ambientes de experimentação. Porém, ele executa código Python real. Não use um REPL embutido como sandbox para usuários não confiáveis: imports, sistema de arquivos, rede, processos e objetos já presentes no namespace podem ser explorados.
InteractiveInterpreter e InteractiveConsole
InteractiveInterpreter cuida da compilação, do estado do namespace e da execução, mas não implementa prompt nem buffering de várias linhas. InteractiveConsole herda essa base e adiciona comportamento parecido com o console padrão, incluindo os prompts principal e secundário.
from code import InteractiveConsole
console = InteractiveConsole()
console.interact(
banner='Console de diagnóstico',
exitmsg='Console encerrado',
)Esse exemplo abre um REPL no processo atual. Tudo que o usuário executar terá as mesmas permissões do programa.
Definir um namespace controlado
O parâmetro locals recebe um mapeamento usado como namespace. Ele permite expor somente objetos específicos e preservar variáveis entre comandos.
from code import InteractiveConsole
contexto = {
'status': lambda: {'fila': 4, 'saude': 'ok'},
'versao': '2.1.0',
}
console = InteractiveConsole(locals=contexto)Uma lista reduzida não transforma o console em ambiente seguro. O próprio Python oferece caminhos para introspecção e recuperação de objetos. Use esse controle para ergonomia e organização, não como fronteira contra atacantes.
Executar uma linha com runsource()
runsource() compila e executa uma string. O retorno informa se é necessária mais entrada: True significa comando incompleto; False significa que o comando foi executado ou rejeitado.
from code import InteractiveInterpreter
interp = InteractiveInterpreter()
precisa_mais = interp.runsource('for i in range(3):')
print(precisa_mais) # TrueEsse protocolo permite escolher entre um prompt principal e um prompt de continuação.
Acumular blocos com push()
InteractiveConsole.push() mantém um buffer interno. Cada linha é adicionada e o conjunto é compilado novamente.
from code import InteractiveConsole
console = InteractiveConsole()
print(console.push('def dobro(x):')) # True
print(console.push(' return x * 2')) # True
print(console.push('')) # False
print(console.push('dobro(5)')) # FalseQuando o bloco termina ou é inválido, o buffer é limpo. resetbuffer() descarta manualmente uma entrada pendente, algo útil após cancelamento.
Detectar código incompleto
A função compile_command() tenta reproduzir a decisão do interpretador real. Ela devolve um objeto de código quando a entrada está completa, None quando falta conteúdo e lança SyntaxError quando existe um erro completo.
from code import compile_command
resultado = compile_command('if ativo:', symbol='single')
assert resultado is NoneO módulo codeop no Python aprofunda o estado de compilação e flags de __future__ para consoles persistentes.
Personalizar a entrada
Subclasses de InteractiveConsole podem sobrescrever raw_input(). Isso permite ler linhas de uma interface gráfica, socket local, editor web ou fila interna.
class ConsoleFila(InteractiveConsole):
def __init__(self, fila, **kwargs):
super().__init__(**kwargs)
self.fila = fila
def raw_input(self, prompt=''):
exibir_prompt(prompt)
return self.fila.get()Não conecte esse método diretamente à internet. Se o console remoto for realmente necessário, imponha autenticação forte, rede restrita, processo dedicado, usuário do sistema sem privilégios, limites de recursos e auditoria.
Capturar erros com write()
Por padrão, mensagens de sintaxe e tracebacks vão para sys.stderr. Sobrescreva write() para armazená-las ou enviá-las à interface.
class ConsoleCaptura(InteractiveConsole):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.erros = []
def write(self, data):
self.erros.append(data)Evite devolver tracebacks completos para usuários externos, pois eles podem revelar caminhos, nomes de módulos e dados. Em interfaces administrativas internas, mantenha registros detalhados em canal protegido.
showsyntaxerror() e showtraceback()
showsyntaxerror() formata erros de compilação, enquanto showtraceback() lida com exceções de execução e remove o frame interno do interpretador. Desde o Python 3.5, exceções encadeadas são exibidas integralmente.
Você pode sobrescrever esses métodos para produzir JSON estruturado ou mensagens localizadas, mas preserve a exceção original em logs para diagnóstico.
Executar objetos de código com runcode()
runcode() recebe um objeto já compilado. Exceções comuns são capturadas e exibidas, mas SystemExit pode propagar. KeyboardInterrupt também pode surgir fora do ponto esperado.
codigo = compile('resultado = 6 * 7', '<console>', 'exec')
interp = InteractiveInterpreter()
interp.runcode(codigo)
print(interp.locals['resultado'])O chamador deve definir uma política para encerramento e interrupção.
local_exit no Python 3.13+
InteractiveConsole e interact() aceitam local_exit=True. Nesse modo, chamadas a exit() e quit() encerram o console e retornam à aplicação, em vez de levantar SystemExit para todo o processo.
console = InteractiveConsole(local_exit=True)
console.interact()Isso melhora a incorporação do REPL, mas não impede que código chame diretamente os._exit(), encerre threads ou altere o processo por outros meios.
Usar code.interact()
code.interact() é uma função de conveniência que cria um console temporário. Ela aceita banner, função de leitura, namespace, mensagem de saída e local_exit.
import code
estado = {'pedido_id': 123, 'modo': 'debug'}
code.interact(
banner='Sessão de suporte local',
local=estado,
exitmsg='',
local_exit=True,
)É útil para abrir um console sob uma flag de desenvolvimento. Garanta que essa flag não fique habilitada em produção.
REPL para depuração
Um padrão é capturar o contexto de um ponto específico e iniciar uma sessão local.
def diagnosticar(objeto):
code.interact(
local={'objeto': objeto, 'resumo': objeto.resumo},
local_exit=True,
)Não inclua tokens, senhas ou objetos com métodos destrutivos. Mesmo um console local pode ser exposto por logs de terminal compartilhados, gravação de sessão ou acesso indevido ao servidor.
Persistência do namespace
Variáveis, funções e classes permanecem no dicionário de locais enquanto a instância existir. Isso permite uma sessão natural, mas também pode reter grandes objetos e aumentar o consumo de memória.
Ofereça um comando para limpar o contexto ou recrie o console após determinado tempo. O guia sobre weakref no Python explica retenção de objetos, embora não substitua uma política explícita de ciclo de vida.
Pickle e objetos definidos no console
Funções e classes criadas pelo interpretador pertencem ao namespace fornecido. Elas só são serializáveis com pickle de forma convencional quando o namespace corresponde a um módulo importável existente. Não dependa de pickle para persistir uma sessão arbitrária.
Prefira salvar dados em formatos definidos e recriar funções a partir de código versionado. Nunca carregue pickle não confiável.
Isolamento real exige outro processo
Remover __builtins__ ou bloquear alguns nomes não cria sandbox. Python permite introspecção profunda, e objetos disponíveis podem abrir caminhos indiretos para funcionalidades perigosas.
Para reduzir impacto, execute o REPL em processo ou container descartável, com usuário sem privilégios, sistema de arquivos limitado, rede desabilitada, CPU e memória controladas e timeout. Mesmo assim, trate-o como execução de código, não como simples entrada de dados.
Testar um console customizado
Teste valores de retorno de push(), namespace, saída capturada, erros de sintaxe, exceções, comandos incompletos, EOF e encerramento local.
def teste_console():
console = ConsoleCaptura(locals={})
assert console.push('x = 10') is False
assert console.locals['x'] == 10
assert console.push('for i in range(2):') is True
console.resetbuffer()Use objetos falsos e não permita acesso real a produção durante testes.
Erros frequentes
- Tratar um namespace reduzido como sandbox.
- Expor o REPL em uma porta pública.
- Deixar consoles de depuração ativos em produção.
- Retornar tracebacks sensíveis ao cliente.
- Ignorar
SystemExiteKeyboardInterrupt. - Reter objetos grandes indefinidamente.
- Tentar persistir funções de sessão com pickle.
Boas práticas
- Use o módulo apenas para usuários confiáveis.
- Prefira processos descartáveis para isolamento.
- Controle namespace e ciclo de vida.
- Capture saída por
write(). - Limite CPU, memória, rede e tempo.
- Desative o recurso por padrão em produção.
- Registre acesso e ações sem expor segredos.
Conclusão
O code no Python facilita a criação de REPLs personalizados com namespace persistente, buffering de blocos, prompts, tratamento de erros e encerramento local. Ele é uma base poderosa para ferramentas de desenvolvimento e diagnóstico.
Seu uso exige uma decisão de segurança explícita: o conteúdo é código executável. Para entradas não confiáveis, use isolamento de sistema operacional, não filtros no namespace. Consulte a documentação oficial do módulo code e a documentação do codeop.







