Python rlcompleter: REPL Completion

Published on: August 13, 2026
Reading time: 5 minutes
Code editor representing REPL completion with Python rlcompleter

Python rlcompleter provides the completion logic commonly used by the interactive interpreter when readline is available. It suggests identifiers, keywords, names in a namespace, and attributes after a dot. The same mechanism can be embedded in custom REPLs, administrative consoles, internal editors, and educational tools.

The module is small, but its security behavior deserves attention. To complete a dotted expression, it resolves the object before the final dot. Ordinary functions are not called, but dynamic attributes and __getattr__() may run. Attribute completion is therefore not guaranteed to be free of side effects.

How the completion protocol works

The main class is rlcompleter.Completer. Its complete(text, state) method is called repeatedly with states 0, 1, 2, and so on until it returns None.

from rlcompleter import Completer

completer = Completer({'client': object(), 'calculate': lambda: None})
state = 0
while True:
    suggestion = completer.complete('cal', state)
    if suggestion is None:
        break
    print(suggestion)
    state += 1

This protocol is designed for readline.set_completer(), but it can also power custom interfaces.

Integrate with readline

On Unix systems with readline, importing rlcompleter usually configures completion automatically for interactive Python. Embedded applications can configure it explicitly.

import readline
from rlcompleter import Completer

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

The backend varies by platform. Some systems use GNU Readline, some use editline, and others have no compatible module. The application should remain useful without completion.

Complete simple names

When the text has no dot, the completer searches the supplied namespace, builtins, and Python keywords.

namespace = {
    'process_file': process_file,
    'process_queue': process_queue,
}
completer = Completer(namespace)

A prefix such as proce can suggest both functions. Keywords such as for, while, and class are also included when they match.

Complete dotted attributes

For dotted names, the module resolves the object on the left and uses dir() to find matching attributes.

import pathlib

completer = Completer({'pathlib': pathlib})
# pathlib.Pa may suggest pathlib.Path

This improves API discovery, but object resolution may execute custom logic. Proxies, ORMs, remote clients, and objects with dynamic attributes can access the network, disk, or a database.

The __getattr__() risk

The documentation notes that obvious function calls are avoided, but __getattr__() may be invoked. Consider a proxy that fetches remote data for unknown attributes.

class Proxy:
    def __getattr__(self, name):
        record_access(name)
        return load_remotely(name)

Completing proxy.lo could trigger work. Do not expose objects with expensive or dangerous resolution behavior in a namespace used by untrusted operators.

Use an explicit namespace

Without a mapping, Completer uses the main environment. Embedded tools should pass an explicit dictionary to avoid accidental suggestions of internal modules, credentials, clients, or diagnostic objects.

public_namespace = {
    'status': public_status,
    'help': show_help,
    'version': '3.0',
}
completer = Completer(public_namespace)

This reduces exposure and improves relevance, but it is not authorization. A real Python REPL still provides introspection paths beyond completion.

Collect all suggestions

A web editor or graphical widget can iterate over states until completion ends.

def collect(completer, text, limit=100):
    results = []
    for state in range(limit):
        item = completer.complete(text, state)
        if item is None:
            break
        if item not in results:
            results.append(item)
    return results

The state limit prevents unexpectedly long loops and large responses. Apply a maximum prefix length as well.

Integrate with InteractiveConsole

The module pairs naturally with the Python code module. The same dictionary can serve both the interpreter and the completer.

import readline
from code import InteractiveConsole
from rlcompleter import Completer

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

For a trusted local operator, this creates an experience close to standard interactive Python.

Use it selectively with cmd.Cmd

cmd.Cmd already has its own command and argument completion protocol. Use rlcompleter only when one command needs to complete Python expressions, not as a replacement for all completion in a Python cmd console.

def complete_inspect(self, text, line, begidx, endidx):
    return collect(self.python_completer, text)

Before returning attributes, verify that the current user may inspect the corresponding object.

Filter private names

An interface can hide suggestions whose final component starts with an underscore.

def public_only(suggestions):
    result = []
    for item in suggestions:
        final = item.rsplit('.', 1)[-1]
        if not final.startswith('_'):
            result.append(item)
    return result

This reduces noise, but it is not access control. A user capable of executing Python can type a private name manually.

Sort and limit results

Large namespaces can return hundreds of options. Remove duplicates, sort results, and cap the response.

results = sorted(set(collect(completer, prefix)))[:30]

A richer editor may rank exact matches first, public prefixes next, and authorized private attributes last.

Cache carefully

Editors may request the same prefix repeatedly. A short cache can help, but it must be invalidated whenever the namespace changes.

from functools import lru_cache

@lru_cache(maxsize=128)
def cached_completion(text, namespace_version):
    return tuple(collect(completer, text))

Include a namespace version in the key or clear the cache after imports, assignments, and context changes.

Completion is not validation

A suggested name is not necessarily safe, correct, or authorized. The completer only discovers names. Compilation and execution remain separate responsibilities.

Use Python codeop to detect incomplete REPL input. Use shlex for shell-like command tokenization.

Platforms without readline

The Completer class still works when readline is unavailable. This makes it suitable for a custom user-interface component.

completer = Completer(namespace)
suggestions = collect(completer, typed_text)

Windows environments may use alternative line-editing libraries, while keeping the same completion collection logic.

Slow attributes and timeouts

The module has no internal timeout. If attribute resolution blocks, the interface may freeze. Avoid objects that perform I/O and run risky completion in a short-lived isolated worker.

Do not attempt to kill arbitrary threads. A disposable process is a safer boundary for potentially blocking objects.

Exception behavior

Exceptions raised while evaluating a dotted expression are caught and silenced, and completion returns None. This keeps the prompt alive but can hide operational problems.

A wrapper may record limited diagnostics for trusted developers without exposing stack traces or object details to users.

Test completion behavior

Test simple names, keywords, dotted attributes, empty namespaces, dynamic proxies, exceptions, duplicate filtering, and result limits.

def test_simple_completion():
    c = Completer({'client': 1, 'classroom': 2})
    items = collect(c, 'cl')
    assert any('client' in item for item in items)
    assert any('classroom' in item for item in items)

Also test your application without readline so the feature remains optional.

Common mistakes

  • Exposing the whole application namespace.
  • Assuming attribute completion cannot cause effects.
  • Treating private-name filtering as security.
  • Returning unlimited suggestions.
  • Keeping stale caches after namespace changes.
  • Depending on GNU Readline everywhere.
  • Confusing discovery with validation.

Best practices

  • Pass an explicit namespace.
  • Expose simple objects without I/O.
  • Limit prefix size, states, and results.
  • Filter noise without claiming isolation.
  • Invalidate caches after changes.
  • Provide a fallback without completion.
  • Test proxies and dynamic attributes.

Conclusion

Python rlcompleter is a compact way to add identifier and attribute suggestions to REPLs, consoles, and editors. It integrates directly with readline, while its class can power independent interfaces.

The main risk is attribute resolution: __getattr__() may run application logic. Use controlled namespaces, predictable objects, limits, and isolation when needed. Consult the official rlcompleter documentation and the readline documentation.

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    Terminal window representing an interactive console built with Python cmd
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python cmd: Build Interactive Consoles

    Learn Python cmd to build interactive consoles with commands, help, history, completion, testing, streams, and secure action control.

    Ler mais

    Tempo de leitura: 4 minutos
    12/08/2026
    Interactive terminal representing a custom REPL built with the Python code module
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python code: Build a Custom REPL

    Learn the Python code module to build custom REPLs, control namespaces, prompts, output, incomplete blocks, errors, and local exit behavior.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Web application code representing WSGI with Python wsgiref
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python wsgiref: WSGI Applications

    Learn Python wsgiref to build and validate WSGI applications, test environ and headers, route requests, and run a local reference

    Ler mais

    Tempo de leitura: 4 minutos
    12/08/2026
    Secure Internet protocol representing Unicode preparation with Python stringprep
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python stringprep: Prepare Unicode

    Learn Python stringprep to apply RFC 3454 tables, map Unicode, reject prohibited characters, and validate bidirectional protocol rules.

    Ler mais

    Tempo de leitura: 5 minutos
    12/08/2026
    Network connections representing non-blocking I/O with Python selectors
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python selectors: Non-Blocking I/O

    Learn Python selectors to monitor many sockets, read and write readiness, timeouts, partial messages, and non-blocking connections safely.

    Ler mais

    Tempo de leitura: 5 minutos
    11/08/2026
    Network data flow representing asynchronous context with Python contextvars
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python contextvars: Async Context State

    Learn Python contextvars to store task-local state, prevent asyncio leaks, copy contexts, propagate metadata, and restore values with tokens.

    Ler mais

    Tempo de leitura: 4 minutos
    11/08/2026