rlcompleter no Python: autocompletar REPL

Publicado em: 13/08/2026
Tempo de leitura: 6 minutos
Editor de código representando autocompletar em REPL com rlcompleter no Python

O módulo rlcompleter no Python fornece a função de autocompletar usada pelo modo interativo quando o readline está disponível. Ele sugere identificadores, palavras-chave, nomes definidos no namespace e atributos depois de um ponto. Esse comportamento pode ser incorporado em REPLs customizados, consoles administrativos, editores internos e ferramentas de ensino.

Apesar de pequeno, o módulo merece atenção de segurança. Para completar uma expressão pontuada, ele tenta resolver o objeto até o último ponto. Funções comuns não são chamadas, mas propriedades dinâmicas e __getattr__() podem ser acionados. Portanto, completar atributos não é necessariamente uma operação sem efeitos colaterais.

Como o rlcompleter funciona

A classe principal é rlcompleter.Completer. Seu método complete(text, state) é chamado repetidamente com estados 0, 1, 2 e assim por diante, até retornar None.

from rlcompleter import Completer

completer = Completer({'cliente': object(), 'calcular': lambda: None})
estado = 0
while True:
    sugestao = completer.complete('cal', estado)
    if sugestao is None:
        break
    print(sugestao)
    estado += 1

Esse protocolo foi desenhado para readline.set_completer(), mas também pode alimentar interfaces próprias.

Integração com readline

Em sistemas Unix com readline, importar rlcompleter normalmente registra automaticamente um completer no modo interativo. Em uma aplicação customizada, a configuração pode ser explícita.

import readline
from rlcompleter import Completer

namespace = {'status': mostrar_status, 'versao': '2.1'}
readline.set_completer(Completer(namespace).complete)
readline.parse_and_bind('tab: complete')

O backend pode variar. Algumas plataformas usam GNU Readline; outras utilizam editline ou não oferecem o módulo. O código deve continuar funcionando mesmo sem autocompletar.

Completar nomes simples

Quando o texto não contém ponto, o completer procura nomes no namespace, em builtins e nas palavras-chave da linguagem.

namespace = {
    'processar_arquivo': processar_arquivo,
    'processar_fila': processar_fila,
}
completer = Completer(namespace)

Uma busca por proce pode sugerir as duas funções. Palavras como for, while e class também aparecem conforme o prefixo.

Completar atributos

Com um ponto, o módulo resolve o objeto à esquerda e usa dir() para encontrar atributos correspondentes.

import pathlib

completer = Completer({'pathlib': pathlib})
# sugestões para pathlib.Pa incluem Path

Esse comportamento melhora a descoberta de APIs, mas pode acionar lógica customizada. Objetos com __getattr__(), proxies remotos, ORMs e propriedades dinâmicas podem acessar rede, disco ou banco.

O risco de __getattr__()

A documentação afirma que funções não são avaliadas durante a resolução, mas chamadas a __getattr__() podem ocorrer. Considere um proxy que busca dados remotamente quando um atributo desconhecido é consultado.

class Proxy:
    def __getattr__(self, nome):
        registrar_acesso(nome)
        return carregar_remotamente(nome)

Autocompletar proxy.cl pode gerar uma consulta. Não exponha objetos com resolução perigosa em namespaces de consoles usados por terceiros.

Namespace explícito

Sem um namespace fornecido, Completer trabalha com o ambiente principal. Em ferramentas embutidas, passe um dicionário explícito para evitar sugestões acidentais de módulos, credenciais ou objetos internos.

namespace_publico = {
    'status': status_publico,
    'ajuda': ajuda,
    'versao': '3.0',
}
completer = Completer(namespace_publico)

Isso melhora a experiência e reduz exposição, mas não substitui autorização. Se o REPL executa Python real, o usuário pode encontrar outros caminhos de introspecção.

Coletar todas as sugestões

Para uma interface web ou editor, crie uma função que itera pelos estados até None.

def completar(completer, texto, limite=100):
    resultados = []
    for estado in range(limite):
        item = completer.complete(texto, estado)
        if item is None:
            break
        if item not in resultados:
            resultados.append(item)
    return resultados

O limite impede loops inesperados e evita respostas enormes. Também aplique tamanho máximo ao prefixo.

Integrar com InteractiveConsole

O módulo combina naturalmente com code no Python. O mesmo dicionário pode ser usado como namespace do interpretador e do completer.

import readline
from code import InteractiveConsole
from rlcompleter import Completer

namespace = {'status': mostrar_status}
readline.set_completer(Completer(namespace).complete)
readline.parse_and_bind('tab: complete')
InteractiveConsole(locals=namespace, local_exit=True).interact()

Se o console for local e confiável, isso cria uma experiência próxima ao interpretador padrão.

Integrar com cmd.Cmd

cmd.Cmd já possui seu próprio protocolo de conclusão para comandos e argumentos. Use rlcompleter quando uma ação específica precisa completar expressões Python, não para substituir todo o mecanismo do cmd no Python.

def complete_inspecionar(self, text, line, begidx, endidx):
    return completar(self.python_completer, text)

Antes de devolver atributos, verifique se o usuário pode inspecionar o objeto correspondente.

Filtrar atributos privados

Uma interface pode remover sugestões que começam com underscore.

def publicas(sugestoes):
    resultado = []
    for item in sugestoes:
        parte = item.rsplit('.', 1)[-1]
        if not parte.startswith('_'):
            resultado.append(item)
    return resultado

Esse filtro reduz ruído, mas não é uma barreira de segurança. Um usuário que executa código pode digitar o nome privado manualmente.

Ordenar e limitar resultados

Namespaces grandes podem produzir centenas de opções. Ordene, remova duplicados e devolva apenas as primeiras sugestões relevantes.

resultados = sorted(set(completar(completer, prefixo)))[:30]

Interfaces gráficas podem classificar nomes exatos primeiro, depois prefixos públicos e por último atributos privados autorizados.

Cache de sugestões

Em editores, o mesmo prefixo pode ser consultado repetidamente. Um cache curto reduz trabalho, mas precisa ser invalidado quando o namespace muda.

from functools import lru_cache

@lru_cache(maxsize=128)
def completar_cacheado(texto, versao_namespace):
    return tuple(completar(completer, texto))

Inclua uma versão do namespace na chave ou limpe o cache após imports, criação de variáveis e troca de contexto.

Autocompletar não valida código

Uma sugestão existente não garante que a expressão seja segura, correta ou autorizada. O completer apenas encontra nomes. A compilação e execução continuam sendo responsabilidades separadas.

Para detectar blocos incompletos em um REPL, use codeop. Para tokenizar comandos parecidos com shell, use o artigo existente sobre shlex.

Plataformas sem readline

A classe Completer pode ser usada mesmo quando readline não existe. Isso permite criar um widget próprio.

completer = Completer(namespace)
sugestoes = completar(completer, texto_digitado)

No Windows, bibliotecas alternativas podem fornecer edição de linha, mas a lógica de coleta continua independente.

Timeout e objetos lentos

O método não possui timeout interno. Se a resolução de atributos for lenta, a interface pode travar. Evite objetos com I/O e execute conclusões complexas em um worker isolado com prazo curto.

Não tente encerrar uma thread arbitrariamente. Prefira processos descartáveis quando o namespace contém objetos potencialmente bloqueantes.

Tratamento de exceções

Exceções levantadas durante a avaliação são capturadas e o módulo retorna None. Isso evita quebrar o prompt, mas pode esconder um problema operacional.

Para depuração, envolva o completer em uma camada que registre falhas de forma limitada, sem expor detalhes ao usuário.

Testes

Teste nomes simples, palavras-chave, atributos, namespace vazio, objetos com __getattr__(), exceções, duplicados e limites.

def test_completar_nome():
    c = Completer({'cliente': 1, 'classe': 2})
    itens = completar(c, 'cl')
    assert any('cliente' in item for item in itens)
    assert any('classe' in item for item in itens)

Inclua testes sem readline para garantir que a aplicação continua utilizável.

Erros frequentes

  • Expor o namespace inteiro sem necessidade.
  • Presumir que completar atributos não causa efeitos.
  • Usar nomes privados como controle de acesso.
  • Não limitar a quantidade de sugestões.
  • Manter cache após alterar o namespace.
  • Depender de GNU Readline em todas as plataformas.
  • Confundir sugestão com validação.

Boas práticas

  • Passe um namespace explícito.
  • Exponha objetos simples e sem I/O.
  • Limite prefixo, estados e resultados.
  • Filtre ruído sem tratar o filtro como segurança.
  • Invalide caches após mudanças.
  • Mantenha fallback sem autocompletar.
  • Teste proxies e atributos dinâmicos.

Conclusão

O rlcompleter no Python é uma forma simples de adicionar sugestões de identificadores e atributos a REPLs, consoles e editores. Ele funciona diretamente com readline, mas sua classe também pode alimentar interfaces próprias.

O principal cuidado está na resolução de atributos: __getattr__() pode executar lógica. Use namespaces controlados, objetos previsíveis, limites e isolamento quando necessário. Consulte a documentação oficial do rlcompleter e a documentação do readline.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Janela de terminal representando console interativo criado com cmd no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    cmd no Python: crie consoles interativos

    Aprenda cmd no Python para criar consoles interativos com comandos, ajuda, histórico, autocompletar, testes e controle seguro de ações.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Terminal interativo representando um REPL customizado com o módulo code no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    code no Python: crie um REPL customizado

    Aprenda o módulo code no Python para criar REPLs customizados, controlar namespaces, prompts, saída, blocos incompletos e encerramento seguro.

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Código de aplicação web representando WSGI com wsgiref no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    wsgiref no Python: aplicações WSGI

    Aprenda wsgiref no Python para criar e validar aplicações WSGI, testar environ, headers, rotas e servidores locais sem usar em

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Protocolo seguro na internet representando preparação Unicode com stringprep no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    stringprep no Python: prepare Unicode

    Aprenda stringprep no Python para aplicar tabelas do RFC 3454, mapear Unicode, bloquear caracteres proibidos e validar regras bidirecionais.

    Ler mais

    Tempo de leitura: 7 minutos
    12/08/2026
    Rede de conexões representando I/O não bloqueante com selectors no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    selectors no Python: I/O não bloqueante

    Aprenda selectors no Python para monitorar vários sockets, eventos de leitura e escrita, timeouts e conexões não bloqueantes com segurança.

    Ler mais

    Tempo de leitura: 5 minutos
    11/08/2026
    Fluxo de dados em rede representando contexto assíncrono com contextvars no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    contextvars no Python: contexto assíncrono

    Aprenda contextvars no Python para armazenar estado por tarefa, evitar vazamentos em asyncio, copiar contextos e restaurar valores com tokens.

    Ler mais

    Tempo de leitura: 6 minutos
    11/08/2026