rlcompleter en Python: autocompletar REPL

Publicado el: 13/08/2026
Tempo de leitura: 6 minutos
Editor de código que representa autocompletado de REPL con rlcompleter en Python

El módulo rlcompleter en Python proporciona la lógica de autocompletado que suele utilizar el intérprete interactivo cuando readline está disponible. Sugiere identificadores, palabras clave, nombres del namespace y atributos después de un punto. El mismo mecanismo puede incorporarse a REPLs personalizados, consolas administrativas, editores internos y herramientas educativas.

Aunque el módulo es pequeño, su comportamiento de seguridad merece atención. Para completar una expresión con puntos, intenta resolver el objeto situado antes del último punto. No llama a funciones normales, pero puede activar atributos dinámicos y __getattr__(). Por tanto, completar atributos no siempre es una operación sin efectos secundarios.

Cómo funciona el protocolo de completado

La clase principal es rlcompleter.Completer. Su método complete(text, state) se llama repetidamente con estados 0, 1, 2 y siguientes hasta que devuelve None.

from rlcompleter import Completer

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

Este protocolo fue diseñado para readline.set_completer(), pero también puede alimentar interfaces personalizadas.

Integración con readline

En sistemas Unix con readline, importar rlcompleter suele configurar automáticamente el autocompletado del modo interactivo. En una aplicación embebida, la configuración puede ser explícita.

import readline
from rlcompleter import Completer

namespace = {'estado': mostrar_estado, 'version': '2.1'}
readline.set_completer(Completer(namespace).complete)
readline.parse_and_bind('tab: complete')

El backend depende de la plataforma. Algunos sistemas usan GNU Readline, otros editline y otros no ofrecen un módulo compatible. La aplicación debe seguir funcionando sin autocompletado.

Completar nombres simples

Cuando el texto no contiene punto, el completer busca en el namespace, en builtins y en las palabras clave de Python.

namespace = {
    'procesar_archivo': procesar_archivo,
    'procesar_cola': procesar_cola,
}
completer = Completer(namespace)

Un prefijo como proce puede sugerir ambas funciones. Palabras como for, while y class también aparecen cuando coinciden.

Completar atributos con puntos

Para nombres con punto, el módulo resuelve el objeto de la izquierda y usa dir() para encontrar atributos.

import pathlib

completer = Completer({'pathlib': pathlib})
# pathlib.Pa puede sugerir pathlib.Path

Esto facilita descubrir APIs, pero la resolución puede ejecutar lógica personalizada. Proxies, ORMs, clientes remotos y objetos con atributos dinámicos pueden acceder a red, disco o base de datos.

El riesgo de __getattr__()

La documentación indica que las funciones evidentes no se evalúan, pero __getattr__() puede ejecutarse. Considera un proxy que carga datos remotos al consultar atributos desconocidos.

class Proxy:
    def __getattr__(self, nombre):
        registrar_acceso(nombre)
        return cargar_remotamente(nombre)

Completar proxy.ca podría generar trabajo real. No expongas objetos con resolución costosa o peligrosa en namespaces utilizados por operadores no confiables.

Usar un namespace explícito

Sin un mapping, Completer utiliza el entorno principal. Las herramientas embebidas deberían pasar un diccionario explícito para evitar sugerencias accidentales de módulos internos, credenciales, clientes o datos de diagnóstico.

namespace_publico = {
    'estado': estado_publico,
    'ayuda': mostrar_ayuda,
    'version': '3.0',
}
completer = Completer(namespace_publico)

Esto reduce exposición y mejora relevancia, pero no es autorización. Un REPL Python real conserva otros caminos de introspección.

Recoger todas las sugerencias

Un editor web o widget gráfico puede iterar por estados hasta que finalice el completado.

def recoger(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

El límite evita bucles inesperados y respuestas enormes. También aplica una longitud máxima al prefijo.

Integración con InteractiveConsole

El módulo combina naturalmente con code en Python. El mismo diccionario puede servir para el intérprete y el completer.

import readline
from code import InteractiveConsole
from rlcompleter import Completer

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

Para un operador local confiable, esto crea una experiencia cercana al intérprete estándar.

Uso selectivo con cmd.Cmd

cmd.Cmd ya dispone de su propio protocolo para completar comandos y argumentos. Utiliza rlcompleter cuando una acción concreta necesite completar expresiones Python, no para sustituir todo el mecanismo de una consola cmd en Python.

def complete_inspeccionar(self, text, line, begidx, endidx):
    return recoger(self.python_completer, text)

Antes de devolver atributos, verifica que el usuario pueda inspeccionar el objeto correspondiente.

Filtrar nombres privados

Una interfaz puede ocultar sugerencias cuyo componente final empiece con underscore.

def solo_publicas(sugerencias):
    resultado = []
    for item in sugerencias:
        final = item.rsplit('.', 1)[-1]
        if not final.startswith('_'):
            resultado.append(item)
    return resultado

El filtro reduce ruido, pero no es control de acceso. Un usuario que ejecuta Python puede escribir manualmente el nombre privado.

Ordenar y limitar resultados

Los namespaces grandes pueden producir cientos de opciones. Elimina duplicados, ordena y limita la respuesta.

resultados = sorted(set(recoger(completer, prefijo)))[:30]

Un editor avanzado puede priorizar coincidencias exactas, luego nombres públicos y finalmente atributos privados autorizados.

Cache con invalidación

Los editores suelen consultar el mismo prefijo varias veces. Un cache corto puede ayudar, pero debe invalidarse cuando cambia el namespace.

from functools import lru_cache

@lru_cache(maxsize=128)
def completar_cache(texto, version_namespace):
    return tuple(recoger(completer, texto))

Incluye una versión del namespace en la clave o limpia el cache después de imports, asignaciones y cambios de contexto.

Autocompletar no valida código

Una sugerencia existente no garantiza que una expresión sea segura, correcta o autorizada. El completer solo descubre nombres. Compilación y ejecución siguen siendo responsabilidades independientes.

Usa codeop en Python para detectar entrada incompleta. Utiliza shlex para comandos con sintaxis similar a shell.

Plataformas sin readline

La clase Completer funciona incluso si readline no está disponible. Esto permite construir un componente propio.

completer = Completer(namespace)
sugerencias = recoger(completer, texto_escrito)

En Windows pueden usarse bibliotecas alternativas de edición de línea manteniendo la misma lógica de colección.

Atributos lentos y timeout

El módulo no incorpora timeout. Si resolver atributos bloquea, la interfaz puede congelarse. Evita objetos con I/O y ejecuta completados arriesgados en un worker aislado y de corta duración.

No intentes matar threads arbitrariamente. Un proceso desechable ofrece una frontera más segura.

Comportamiento ante excepciones

Las excepciones durante la evaluación de expresiones con puntos se capturan y silencian; el método devuelve None. Esto mantiene vivo el prompt, pero puede ocultar problemas operativos.

Una capa envolvente puede registrar diagnósticos limitados para desarrolladores confiables sin mostrar tracebacks ni detalles de objetos.

Pruebas

Prueba nombres simples, palabras clave, atributos, namespaces vacíos, proxies dinámicos, excepciones, duplicados y límites.

def test_completado_simple():
    c = Completer({'cliente': 1, 'clase': 2})
    items = recoger(c, 'cl')
    assert any('cliente' in item for item in items)
    assert any('clase' in item for item in items)

También prueba la aplicación sin readline para asegurar que la función sea opcional.

Errores frecuentes

  • Exponer todo el namespace de la aplicación.
  • Suponer que completar atributos no causa efectos.
  • Tratar el filtro de privados como seguridad.
  • Devolver sugerencias ilimitadas.
  • Mantener caches obsoletos.
  • Depender de GNU Readline en todas las plataformas.
  • Confundir descubrimiento con validación.

Buenas prácticas

  • Pasa un namespace explícito.
  • Expón objetos simples y sin I/O.
  • Limita prefijo, estados y resultados.
  • Filtra ruido sin afirmar aislamiento.
  • Invalida caches después de cambios.
  • Ofrece fallback sin autocompletar.
  • Prueba proxies y atributos dinámicos.

Conclusión

rlcompleter en Python es una forma compacta de añadir sugerencias de identificadores y atributos a REPLs, consolas y editores. Se integra directamente con readline, y su clase también puede alimentar interfaces independientes.

El principal riesgo está en la resolución de atributos: __getattr__() puede ejecutar lógica. Usa namespaces controlados, objetos predecibles, límites y aislamiento cuando sea necesario. Consulta la documentación oficial de rlcompleter y la documentación de readline.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Ventana de terminal que representa una consola interactiva creada con cmd en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    cmd en Python: crea consolas interactivas

    Aprende cmd en Python para crear consolas interactivas con comandos, ayuda, historial, autocompletado, pruebas y control seguro de acciones.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Terminal interactivo que representa un REPL personalizado creado con el módulo code en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    code en Python: crea un REPL personalizado

    Aprende el módulo code en Python para crear REPLs personalizados, controlar namespaces, prompts, salida, bloques incompletos y cierre local.

    Ler mais

    Tempo de leitura: 6 minutos
    12/08/2026
    Código de aplicación web que representa WSGI con wsgiref en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    wsgiref en Python: aplicaciones WSGI

    Aprende wsgiref en Python para crear y validar aplicaciones WSGI, probar environ y headers, enrutar solicitudes y ejecutar un servidor

    Ler mais

    Tempo de leitura: 4 minutos
    12/08/2026
    Protocolo seguro de Internet que representa preparación Unicode con stringprep en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    stringprep en Python: prepara Unicode

    Aprende stringprep en Python para aplicar tablas RFC 3454, mapear Unicode, rechazar caracteres prohibidos y validar reglas bidireccionales.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Red de conexiones que representa I/O no bloqueante con selectors en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    selectors en Python: I/O no bloqueante

    Aprende selectors en Python para monitorizar muchos sockets, eventos de lectura y escritura, timeouts y conexiones no bloqueantes con seguridad.

    Ler mais

    Tempo de leitura: 4 minutos
    11/08/2026
    Flujo de datos en red que representa contexto asíncrono con contextvars en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    contextvars en Python: contexto asíncrono

    Aprende contextvars en Python para guardar estado por tarea, evitar fugas en asyncio, copiar contextos y restaurar valores con tokens.

    Ler mais

    Tempo de leitura: 5 minutos
    11/08/2026