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 += 1Este 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.PathEsto 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 resultadosEl 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 resultadoEl 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.







