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 += 1Esse 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 PathEsse 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 resultadosO 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 resultadoEsse 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.







