The readline module adds line editing, command history, and tab completion to interactive terminal programs. It can affect the traditional Python prompt and ordinary input() calls, allowing users to navigate with arrow keys, reuse previous entries, and complete words without retyping them.
Despite its name, the module may be backed by GNU Readline or the compatible libedit implementation. That difference affects configuration files, key bindings, history formats, and small API details. Modern Python also introduces another distinction: the new REPL added in Python 3.13 does not use readline by default.
Availability
readline is optional and normally available on Unix. It is not supported on Android, iOS, or WASI. A distributor may build CPython without it, so portable software should handle ImportError.
try:
import readline
except ImportError:
readline = None
Windows may use third-party alternatives, but those are not the standard module. Do not make terminal convenience features a hard dependency when the main application can still run without them.
Detect the backend
Since Python 3.13, readline.backend reports either readline or editline.
import readline
print(readline.backend)
macOS commonly uses libedit. GNU Readline normally reads ~/.inputrc, while libedit commonly reads ~/.editrc. Their command syntax is different, and their history files may not be interchangeable.
Enable Tab completion
The simplest setup uses rlcompleter, which completes Python names in the current namespace.
import readline
import rlcompleter
if readline.backend == "editline":
readline.parse_and_bind("bind ^I rl_complete")
else:
readline.parse_and_bind("tab: complete")
The guide to Python rlcompleter covers identifier completion in more detail. Custom command applications usually need their own completer.
Write a custom completer
A completer receives text and state. It returns one match for each state value and eventually returns None.
import readline
COMMANDS = ["configure", "help", "list", "open", "quit", "run"]
def complete(text, state):
matches = [item for item in COMMANDS if item.startswith(text)]
if state < len(matches):
return matches[state]
return None
readline.set_completer(complete)
readline.set_completer_delims(" \t\n")
readline.parse_and_bind("tab: complete")
Keep completion fast. A function that performs a network request, scans a huge directory, or queries a database on every Tab press creates a poor interface.
Completion delimiters
set_completer_delims() controls which characters split the current word. File paths, dotted names, and colon-separated values may require removing characters from the default set.
delimiters = readline.get_completer_delims()
readline.set_completer_delims(delimiters.replace("/", ""))
get_begidx() and get_endidx() expose the active completion range. GNU Readline and libedit can return different indexes for similar editing states, so cross-platform tests are important.
In-memory history
The global history list can be inspected and modified.
import readline
readline.add_history("status")
readline.add_history("list projects")
count = readline.get_current_history_length()
for index in range(1, count + 1):
print(index, readline.get_history_item(index))
get_history_item() uses one-based indexes. remove_history_item() and replace_history_item() use zero-based positions. Mixing those conventions is a common bug.
Do not store secrets
Tokens, passwords, private keys, recovery codes, and personal data must not be written to command history. Use getpass for passwords and disable automatic history around sensitive prompts.
import getpass
import readline
readline.set_auto_history(False)
try:
secret = getpass.getpass("Token: ")
finally:
readline.set_auto_history(True)
The setting is process-global. Restore it after errors and never log the captured value.
Load and save a history file
A persistent file makes commands available across sessions.
import atexit
import os
import readline
history_path = os.path.expanduser("~/.my_app_history")
try:
readline.read_history_file(history_path)
except FileNotFoundError:
pass
readline.set_history_length(1000)
atexit.register(readline.write_history_file, history_path)
Python 3.14 adds auditing events to history and initialization-file access. Security hooks may record or reject these operations.
Protect the history file
History often reveals paths, hostnames, arguments, and operational details. Create it in a private directory and use restrictive permissions where the platform supports them.
from pathlib import Path
import os
path = Path.home() / ".my_app_history"
if not path.exists():
fd = os.open(path, os.O_CREAT | os.O_WRONLY, 0o600)
os.close(fd)
Unix mode bits are not a universal security model. Windows access control requires different assumptions.
Concurrent sessions
write_history_file() overwrites the destination. Two open sessions can lose each other’s commands. When available, append_history_file() appends only new entries.
import atexit
import readline
starting_count = readline.get_current_history_length()
def save_incremental(path):
current = readline.get_current_history_length()
new_items = max(0, current - starting_count)
readline.set_history_length(1000)
if new_items:
readline.append_history_file(new_items, path)
atexit.register(save_incremental, history_path)
Appending still does not guarantee perfect coordination between simultaneous writers. Use file locking or per-session history when consistency matters.
Limit growth
set_history_length() controls the number of lines saved. A negative value means unlimited history and may create an ever-growing file.
Choose a practical line limit and, for tools with large commands, consider a byte-size limit or rotation policy.
Modify the current line buffer
get_line_buffer() returns the current input. insert_text() inserts at the cursor, and redisplay() refreshes the screen.
import readline
def add_default_text():
if not readline.get_line_buffer():
readline.insert_text("list ")
readline.redisplay()
readline.set_startup_hook(add_default_text)
A startup hook runs before the first prompt is printed. A pre-input hook, when supported, runs after the prompt and before character input begins.
Avoid unsafe automatic insertion
Text inserted into a prompt may look ready for execution. Do not construct commands from untrusted remote content, filenames, or pasted data without validation. The user should retain control before pressing Enter.
Configuration files
read_init_file() loads a configuration file, while parse_and_bind() applies one line directly.
if readline.backend == "readline":
readline.parse_and_bind("set editing-mode vi")
else:
readline.parse_and_bind("bind -v")
Do not automatically load a configuration file from an untrusted location. Readline configuration can define macros and change important key behavior.
Use with input()
After importing and configuring the module, regular input() calls gain editing and history behavior.
while True:
try:
command = input("app> ").strip()
except EOFError:
break
except KeyboardInterrupt:
print()
continue
if command == "quit":
break
execute(command)
Handle EOF and Ctrl+C without exposing a stack trace. The guide to Python signal explains interruption and cooperative shutdown.
The new Python REPL
The current documentation notes that the new REPL introduced in Python 3.13 does not use readline. Set PYTHON_BASIC_REPL to use the basic compatible REPL.
This limitation applies to the interpreter’s new interactive prompt. Applications that call input() can still configure readline normally.
Testing
Test GNU Readline and libedit, missing-module behavior, absent and read-only history files, concurrent sessions, Unicode input, zero and multiple completion matches, Ctrl+C, EOF, and non-interactive terminals.
Pseudo-terminal tests can emulate a real TTY. A later guide in this batch covers the Unix pty module.
Common mistakes
Common failures include assuming GNU Readline on macOS, sharing GNU and libedit configuration, storing secrets, leaving unlimited history, overwriting concurrent sessions, running slow operations in the completer, confusing history index bases, and requiring the module on unsupported platforms.
Conclusion
readline turns basic prompts into productive terminal interfaces with editing, history, and completion. Reliable use requires backend detection, secure history handling, bounded storage, and graceful fallback.
Keep completers fast, protect history files, and test both GNU Readline and libedit. Consult the official readline documentation and the GNU Readline manual.







