The standard Python readline extension statically linked against the GNU readline library.
—
Utility modules and scripts that complement the core gnureadline functionality, including system integration and alternative import mechanisms.
Pure Python wrapper module that imports all gnureadline functionality for systems without a built-in readline module.
# All gnureadline functions are available through this module
from gnureadline import *
from gnureadline import __doc__This module is designed for systems like ActiveState Python that have no default readline module at all.
# For systems without any readline module
import readline # This will import the gnureadline wrapper
# All gnureadline functions are now available as readline functions
readline.add_history("test command")
readline.set_completer(my_completer)Warning: This module should not be used to override an existing system readline. Use the override_readline module instead for that purpose.
Installation utility for system-wide readline replacement via Python's site customization mechanism. This script safely overrides the default readline module with gnureadline.
def main() -> int:
"""
Main entry point for override installation.
Returns:
int: Exit code (0 for success, 1 for failure)
"""
def check_module(module_name: str):
"""
Import and analyze a readline module.
Parameters:
- module_name: Name of module to check ('readline' or 'gnureadline')
Returns:
module or None: Imported module or None if import failed
"""
def install_override(customize_path: str):
"""
Install readline override in specified customization file.
Parameters:
- customize_path: Path to sitecustomize.py or usercustomize.py
"""
def override_usercustomize() -> bool:
"""
Install override in user site customization.
Returns:
bool: True if successful, False if failed
"""
def override_sitecustomize() -> bool:
"""
Install override in site customization.
Returns:
bool: True if successful, False if failed
"""The recommended way to use the override module is as a script:
# Install override for current Python interpreter (tries user site first)
python -m override_readline
# Install in site customization (system-wide, skips user site)
python -s -m override_readline
# For specific Python version
python3.11 -m override_readlineimport override_readline
# Check what readline modules are available
print("Checking available readline modules:")
readline_mod = override_readline.check_module("readline")
gnureadline_mod = override_readline.check_module("gnureadline")
if gnureadline_mod:
print("gnureadline is available")
if readline_mod == gnureadline_mod:
print("readline is already overridden with gnureadline")
else:
print("readline is using a different implementation")
# Install override programmatically
try:
success = override_readline.override_usercustomize()
if success:
print("Override installed in user customization")
else:
success = override_readline.override_sitecustomize()
if success:
print("Override installed in site customization")
else:
print("Failed to install override")
except Exception as e:
print(f"Error installing override: {e}")For advanced users who want to customize the override behavior:
# Example custom sitecustomize.py content
import sys
def setup_gnureadline():
"""Custom gnureadline setup with additional configuration."""
try:
import gnureadline as readline
# Custom configuration
readline.set_history_length(2000)
readline.parse_and_bind("set bell-style none")
readline.parse_and_bind("set completion-ignore-case on")
# Load history file
import os
import atexit
history_file = os.path.expanduser("~/.python_history")
try:
readline.read_history_file(history_file)
except FileNotFoundError:
pass
# Save history on exit
def save_history():
try:
readline.write_history_file(history_file)
except OSError:
pass
atexit.register(save_history)
# Add interactive hook message
def add_override_message():
try:
old_hook = sys.__interactivehook__
except AttributeError:
return
def hook():
old_hook()
print("Using GNU readline with custom configuration")
sys.__interactivehook__ = hook
add_override_message()
except ImportError:
import readline
# Make readline available globally
sys.modules["readline"] = readline
# Set up readline override
setup_gnureadline()# Environment-aware override setup
import os
import sys
def setup_readline_for_environment():
"""Set up readline based on environment."""
try:
import gnureadline as readline
# Different configs for different environments
if os.environ.get('DEVELOPMENT_MODE'):
# Development environment - more verbose
readline.parse_and_bind("set bell-style audible")
readline.set_history_length(5000)
# Enable all completions
readline.parse_and_bind("set completion-ignore-case on")
readline.parse_and_bind("set show-all-if-ambiguous on")
elif os.environ.get('PRODUCTION_MODE'):
# Production environment - minimal
readline.parse_and_bind("set bell-style none")
readline.set_history_length(100)
else:
# Default environment
readline.set_history_length(1000)
readline.parse_and_bind("set bell-style none")
# Environment-specific history files
env_name = os.environ.get('ENVIRONMENT', 'default')
history_file = os.path.expanduser(f"~/.python_history_{env_name}")
try:
readline.read_history_file(history_file)
except FileNotFoundError:
pass
import atexit
atexit.register(lambda: readline.write_history_file(history_file))
except ImportError:
import readline
sys.modules["readline"] = readline
setup_readline_for_environment()# Application-specific readline configuration
import sys
import os
class ApplicationReadline:
"""Application-specific readline wrapper."""
def __init__(self, app_name):
self.app_name = app_name
self.setup_readline()
def setup_readline(self):
"""Set up readline for this application."""
try:
import gnureadline as readline
self.readline = readline
# App-specific configuration
config_file = os.path.expanduser(f"~/.{self.app_name}_inputrc")
if os.path.exists(config_file):
readline.read_init_file(config_file)
# App-specific history
self.history_file = os.path.expanduser(f"~/.{self.app_name}_history")
try:
readline.read_history_file(self.history_file)
except FileNotFoundError:
pass
# Set up save on exit
import atexit
atexit.register(self.save_history)
# Custom completer
readline.set_completer(self.app_completer)
readline.parse_and_bind("tab: complete")
except ImportError:
import readline
self.readline = readline
def app_completer(self, text, state):
"""Application-specific completer."""
# Implement app-specific completion logic
app_commands = ['start', 'stop', 'status', 'config', 'help', 'quit']
matches = [cmd for cmd in app_commands if cmd.startswith(text)]
try:
return matches[state]
except IndexError:
return None
def save_history(self):
"""Save application history."""
try:
self.readline.write_history_file(self.history_file)
except (OSError, AttributeError):
pass
def get_readline(self):
"""Get the configured readline module."""
return self.readline
# Usage in application
def setup_app_readline(app_name):
"""Set up application-specific readline."""
app_readline = ApplicationReadline(app_name)
readline = app_readline.get_readline()
# Make it available as the readline module
sys.modules["readline"] = readline
return readline
# Example usage
# readline = setup_app_readline("myapp")import sys
def diagnose_readline():
"""Diagnose readline configuration and issues."""
print("=== Readline Diagnosis ===")
# Check if readline is available
try:
import readline
print(f"✓ readline module imported: {readline.__file__}")
print(f" Documentation: {readline.__doc__[:100]}...")
# Check if it's GNU readline or libedit
if hasattr(readline, 'backend'):
print(f" Backend: {readline.backend}")
elif "GNU" in readline.__doc__:
print(" Backend: GNU readline")
elif "libedit" in readline.__doc__:
print(" Backend: libedit")
else:
print(" Backend: unknown")
except ImportError:
print("✗ readline module not available")
return
# Check gnureadline availability
try:
import gnureadline
print(f"✓ gnureadline available: {gnureadline.__file__}")
except ImportError:
print("✗ gnureadline not available")
# Check if readline is overridden
try:
import readline
import gnureadline
if readline is gnureadline:
print("✓ readline is overridden with gnureadline")
else:
print("⚠ readline is not overridden")
except ImportError:
pass
# Check site customization
try:
import sitecustomize
print(f"✓ sitecustomize found: {sitecustomize.__file__}")
except ImportError:
print("- sitecustomize not found")
try:
import usercustomize
print(f"✓ usercustomize found: {usercustomize.__file__}")
except ImportError:
print("- usercustomize not found")
# Check history functionality
try:
readline.add_history("test")
if readline.get_current_history_length() > 0:
print("✓ History functionality working")
else:
print("⚠ History functionality not working")
except Exception as e:
print(f"✗ History error: {e}")
# Check completion functionality
try:
readline.set_completer(lambda text, state: None)
print("✓ Completion functionality working")
except Exception as e:
print(f"✗ Completion error: {e}")
print("=== End Diagnosis ===")
# diagnose_readline() # Uncomment to run diagnosisdef verify_gnureadline_installation():
"""Verify that gnureadline is properly installed and configured."""
issues = []
# Check basic import
try:
import gnureadline
except ImportError:
issues.append("gnureadline cannot be imported - package not installed")
return issues
# Check C extension
try:
gnureadline.add_history("test")
gnureadline.clear_history()
except Exception as e:
issues.append(f"gnureadline C extension not working: {e}")
# Check override modules
try:
import readline as readline_module
import override_readline
except ImportError as e:
issues.append(f"Override modules not available: {e}")
# Check if override is recommended
try:
import readline
if "libedit" in readline.__doc__:
issues.append("System readline is libedit - consider running 'python -m override_readline'")
except ImportError:
pass
if not issues:
print("✓ gnureadline installation is working correctly")
else:
print("Issues found:")
for issue in issues:
print(f" ⚠ {issue}")
return issues
# verify_gnureadline_installation() # Uncomment to run verificationInstall with Tessl CLI
npx tessl i tessl/pypi-gnureadline