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

    Desarrollador configurando un servidor HTTPS y certificado TLS con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    HTTPSServer: crea un servidor HTTPS local en Python

    Aprende HTTPSServer en Python para crear servicios HTTPS locales, configurar certificados, usar hilos y comprender sus límites.

    Ler mais

    Tempo de leitura: 4 minutos
    08/10/2026
    Archivos protegidos que representan extracción segura de TAR con Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tarfile extraction_filter: extrae TAR con seguridad

    Aprende tarfile extraction_filter en Python para extraer archivos TAR con validación, seguridad y control de rutas.

    Ler mais

    Tempo de leitura: 6 minutos
    08/10/2026
    Código Python mostrando avisos controlados con catch_warnings
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    catch_warnings: captura warnings en pruebas Python

    Aprende catch_warnings en Python para capturar, probar y controlar avisos con filtros específicos y alcance seguro.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código Python que representa referencias persistentes de pickle
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickle persistent_id: serializa referencias externas

    Aprende pickle persistent_id en Python para referencias externas estables, validación, seguridad, rendimiento y compatibilidad.

    Ler mais

    Tempo de leitura: 5 minutos
    07/10/2026
    Código binario que representa buffers y vistas de memoria en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    memoryview.count: cuenta valores sin copiar buffers

    Aprende memoryview.count en Python para contar bytes y valores en buffers sin copias, con formatos, límites y buenas prácticas.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026
    Código Python y anotaciones de tipos
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    annotationlib: evita imports circulares en anotaciones

    Aprende annotationlib en Python para inspeccionar anotaciones diferidas, evitar imports circulares y crear herramientas seguras.

    Ler mais

    Tempo de leitura: 6 minutos
    06/10/2026