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 += 1This 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.PathThis 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 resultsThe 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 resultThis 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.







