O módulo readline adiciona edição de linha, histórico de comandos e autocompletar a aplicações interativas executadas no terminal. Ele influencia o prompt tradicional do Python e também chamadas de input(), permitindo navegar com as setas, reutilizar entradas anteriores e completar palavras com Tab.
Apesar do nome, o módulo pode usar GNU Readline ou a implementação compatível libedit. Essa diferença afeta arquivos de configuração, atalhos, histórico e alguns detalhes da API. Em Python moderno, também é importante saber que o novo REPL introduzido no Python 3.13 não depende de readline por padrão.
Disponibilidade
readline é um módulo opcional e normalmente está disponível em sistemas Unix. Ele não é suportado em Android, iOS ou WASI. Algumas distribuições podem compilar o Python sem a biblioteca, portanto uma aplicação portátil deve tratar ImportError.
try:
import readline
except ImportError:
readline = None
No Windows, bibliotecas de terceiros podem oferecer comportamento semelhante, mas não fazem parte do módulo padrão. Não force a importação quando a aplicação precisa funcionar em vários sistemas.
Descobrir o backend
Desde o Python 3.13, readline.backend informa se a implementação é readline ou editline.
import readline
print(readline.backend)
No macOS, libedit é comum. O arquivo de configuração costuma ser ~/.editrc, enquanto GNU Readline usa normalmente ~/.inputrc. Não copie comandos de configuração entre os dois formatos sem verificar o backend.
Ativar autocomplete com Tab
O caso mais simples usa rlcompleter, que completa nomes disponíveis no namespace Python.
import readline
import rlcompleter
if readline.backend == "editline":
readline.parse_and_bind("bind ^I rl_complete")
else:
readline.parse_and_bind("tab: complete")
O módulo rlcompleter no Python explica como completar identificadores e objetos. Para aplicações próprias, um completer customizado oferece mais controle.
Criar um completer customizado
A função recebe text e state. Ela deve retornar uma sugestão por chamada e terminar com None.
import readline
COMANDOS = ["abrir", "ajuda", "configurar", "executar", "sair"]
def completar(texto, estado):
opcoes = [item for item in COMANDOS if item.startswith(texto)]
if estado < len(opcoes):
return opcoes[estado]
return None
readline.set_completer(completar)
readline.set_completer_delims(" \t\n")
readline.parse_and_bind("tab: complete")
Evite acessar rede, banco de dados ou filesystem pesado a cada pressionamento de Tab. O completer é chamado repetidamente e precisa responder rápido.
Delimitadores de palavras
set_completer_delims() define quais caracteres separam a palavra atual. Para comandos com caminhos, pontos, barras ou dois-pontos, o padrão pode cortar o texto cedo demais.
delimitadores = readline.get_completer_delims()
readline.set_completer_delims(delimitadores.replace("/", ""))
Os índices get_begidx() e get_endidx() mostram a região do buffer sendo completada. GNU Readline e libedit podem devolver valores diferentes em cenários semelhantes, então teste nos sistemas suportados.
Histórico em memória
O histórico global pode ser consultado e alterado programaticamente.
import readline
readline.add_history("status")
readline.add_history("listar projetos")
quantidade = readline.get_current_history_length()
for indice in range(1, quantidade + 1):
print(indice, readline.get_history_item(indice))
get_history_item() usa índice começando em 1. Já remove_history_item() e replace_history_item() usam posição começando em zero. Essa diferença é uma fonte comum de erros.
Não grave segredos no histórico
Aplicações que solicitam tokens, senhas, chaves privadas ou dados pessoais não devem permitir que essas entradas sejam gravadas. Use getpass para senhas e desative o histórico automático ao redor de prompts sensíveis.
import getpass
import readline
readline.set_auto_history(False)
segredo = getpass.getpass("Token: ")
readline.set_auto_history(True)
O estado é global ao processo. Restaure-o mesmo em caso de erro e não registre o valor em logs. Para aplicações complexas, encapsule a mudança em um context manager.
Ler e salvar histórico
Um arquivo de histórico torna comandos disponíveis em sessões futuras.
import atexit
import os
import readline
historico = os.path.expanduser("~/.meu_app_history")
try:
readline.read_history_file(historico)
except FileNotFoundError:
pass
readline.set_history_length(1000)
atexit.register(readline.write_history_file, historico)
No Python 3.14, leitura e escrita desses arquivos geram eventos de auditoria. Ambientes com hooks de segurança podem registrar ou bloquear a operação.
Permissões do arquivo
O histórico pode conter caminhos, nomes de servidores, argumentos e outros dados sensíveis. Crie o arquivo com permissões restritas e evite diretórios compartilhados.
from pathlib import Path
import os
caminho = Path.home() / ".meu_app_history"
if not caminho.exists():
descritor = os.open(caminho, os.O_CREAT | os.O_WRONLY, 0o600)
os.close(descritor)
Em sistemas não Unix, a política de permissões é diferente. Não trate 0o600 como garantia universal.
Sessões concorrentes
write_history_file() sobrescreve o arquivo. Duas sessões abertas podem perder comandos uma da outra. Quando disponível, append_history_file() acrescenta apenas as entradas novas.
import atexit
import readline
inicio = readline.get_current_history_length()
def salvar_incremental(caminho):
atual = readline.get_current_history_length()
novos = max(0, atual - inicio)
readline.set_history_length(1000)
if novos:
readline.append_history_file(novos, caminho)
atexit.register(salvar_incremental, historico)
Mesmo o append pode sofrer corrida quando várias instâncias escrevem ao mesmo tempo. Para consistência forte, use lock de arquivo ou histórico separado por sessão.
Limitar crescimento
set_history_length() controla quantas linhas são mantidas ao escrever. Valor negativo significa ilimitado e pode fazer o arquivo crescer indefinidamente.
Defina um limite compatível com o uso. Ferramentas com comandos extensos podem medir também o tamanho em bytes e rotacionar o arquivo.
Editar o buffer atual
get_line_buffer() retorna o texto digitado. insert_text() insere conteúdo no cursor e redisplay() atualiza a tela.
import readline
def preencher_padrao():
if not readline.get_line_buffer():
readline.insert_text("listar ")
readline.redisplay()
readline.set_startup_hook(preencher_padrao)
O startup hook roda antes do prompt ser exibido. O pre-input hook, quando disponível, roda depois do prompt e antes da leitura dos caracteres.
Não insira dados não confiáveis
Texto inserido no buffer pode parecer uma instrução pronta para execução. Não preencha automaticamente comandos construídos com entrada externa, nomes de arquivos maliciosos ou conteúdo remoto sem escapar e validar.
O usuário deve continuar no controle antes de pressionar Enter.
Arquivo de configuração
read_init_file() carrega um arquivo de configuração. parse_and_bind() aplica uma linha diretamente.
if readline.backend == "readline":
readline.parse_and_bind("set editing-mode vi")
else:
readline.parse_and_bind("bind -v")
Não carregue automaticamente um arquivo fornecido por usuário não confiável. A configuração pode alterar atalhos, macros e comportamento interativo.
Integração com input()
Depois de importar e configurar readline, chamadas comuns de input() passam a usar edição e histórico.
while True:
try:
comando = input("app> ").strip()
except EOFError:
break
except KeyboardInterrupt:
print()
continue
if comando == "sair":
break
executar(comando)
Trate EOF e Ctrl+C sem imprimir stack trace para o usuário. O conjunto sobre signal no Python explica interrupções e encerramento cooperativo.
Novo REPL do Python
A documentação atual informa que o novo REPL introduzido no Python 3.13 não usa readline. Para voltar ao REPL básico compatível, defina a variável PYTHON_BASIC_REPL.
Isso não impede que aplicações próprias usem readline com input(); a observação vale especificamente para o novo prompt interativo do interpretador.
Testes
Teste GNU Readline e libedit, ausência do módulo, histórico inexistente, arquivo sem permissão, duas sessões concorrentes, limite de histórico, Tab com zero e várias sugestões, caracteres Unicode, interrupção por Ctrl+C e execução em terminal não interativo.
Automatizar testes de terminal pode exigir pseudo-terminal. O próximo conjunto sobre pty mostrará como simular uma sessão TTY em Unix.
Erros comuns
Os erros mais frequentes são presumir GNU Readline no macOS, usar a mesma configuração em libedit, salvar senhas no histórico, deixar o histórico ilimitado, sobrescrever sessões concorrentes, executar I/O lento no completer, esquecer que índices de histórico usam bases diferentes e depender do módulo em plataformas não suportadas.
Conclusão
readline transforma prompts simples em interfaces de terminal mais produtivas, com edição, histórico e autocomplete. Para usá-lo bem, trate backend, disponibilidade, segurança do histórico e concorrência.
Prefira completadores rápidos, limite o arquivo, não grave segredos e teste GNU Readline e libedit. Consulte a documentação oficial de readline e o manual GNU Readline.







