CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-gnureadline

The standard Python readline extension statically linked against the GNU readline library.

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities

Utility modules and scripts that complement the core gnureadline functionality, including system integration and alternative import mechanisms.

readline.py Module

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__

Usage

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.

override_readline Module

Installation utility for system-wide readline replacement via Python's site customization mechanism. This script safely overrides the default readline module with gnureadline.

Core Functions

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
    """

Command-Line Usage

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_readline

Usage Examples

import 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}")

Advanced Integration Examples

Custom Site Customization

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-Specific Configuration

# 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 Override

# 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")

Troubleshooting Utilities

Diagnostic Functions

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 diagnosis

Installation Verification

def 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 verification

Install with Tessl CLI

npx tessl i tessl/pypi-gnureadline

docs

completion.md

history.md

hooks.md

index.md

line-editing.md

utilities.md

tile.json