Skip to main content

A very comprehensive terminal input module with no external dependencies

Project description

Robust Input Module

A comprehensive and robust input routine for command-line applications in Python. This module provides a highly configurable input function with advanced terminal control, validation, and user experience features.

Features

Core Input Capabilities

  • Real-time Character Input: Character-by-character processing with immediate feedback
  • Cursor Movement: Full left/right arrow key support for in-place editing
  • Backspace Support: Delete characters with proper cursor positioning
  • Default Values: Built-in default value handling with validation
  • Cross-platform: Works in both terminal and non-terminal environments

Advanced Validation System

  • Length Validation: Minimum and maximum length constraints
  • Type Validation: Automatic casting to int, float, bool, str, and custom types
  • Pattern Validation: Regular expression pattern matching
  • Choice Validation: Selection from predefined options
  • Custom Validators: User-defined validation functions
  • Composite Validation: Multiple validation layers applied sequentially

Professional User Experience

  • Smart Error Display: Errors appear below input line without scrolling
  • Persistent Error Messages: Errors stay visible until next validation
  • Instant Feedback: No artificial delays - immediate validation response
  • Screen Real Estate Reuse: Cursor repositioning prevents screen clutter
  • Clean Terminal Management: Proper terminal state restoration

Security & Styling

  • Password Masking: Secure input with asterisk masking
  • ANSI Styling: Full color and text style support
  • Customizable Messages: User-defined prompts and error messages
  • Graceful Degradation: Fallback behavior for non-terminal environments

Requirements

  • Python 3.6+
  • Linux/Unix environment (uses termios and tty modules)
  • Standard library only (no external dependencies)

Installation

Simply copy the robust_input.py file to your project directory.

Usage

Basic Examples

import robust_input as ri

# Simple string input
name = ri.get_input(prompt="Enter your name")
print(f"Hello, {name}!")

# Integer input with validation
age = ri.get_input(
    prompt="Enter your age",
    target_type=int,
    min_length=1,
    max_length=3,
    custom_validator=lambda x: 1 <= int(x) <= 120,
    error_message="Age must be between 1 and 120"
)

# String input with length constraints
username = ri.get_input(
    prompt="Choose a username",
    min_length=3,
    max_length=20,
    allow_empty=False,
    error_message="Username must be 3-20 characters"
)

# Choice selection
color = ri.get_input(
    prompt="Select your favorite color",
    choices=["red", "green", "blue", "yellow"],
    default="blue",
    error_message="Please choose from the available colors"
)

Password and Security

import robust_input as ri

# Password input with masking
password = ri.get_password(
    prompt="Enter your password",
    min_length=8,
    pattern=r'^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$',
    error_message="Password must be at least 8 characters with letters and numbers"
)

# Secure input with custom validation
def strong_password(pwd: str) -> bool:
    return (len(pwd) >= 8 and 
            any(c.isupper() for c in pwd) and 
            any(c.islower() for c in pwd) and 
            any(c.isdigit() for c in pwd))

secure_pwd = ri.get_input(
    prompt="Create a strong password",
    is_password=True,
    custom_validator=strong_password,
    error_message="Password must have uppercase, lowercase, and numbers"
)

Advanced Validation

import robust_input as ri
import re

# Email validation
email = ri.get_input(
    prompt="Enter your email",
    pattern=r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
    error_message="Please enter a valid email address"
)

# Custom validation function
def is_prime(value: str) -> bool:
    try:
        n = int(value)
        if n < 2:
            return False
        for i in range(2, int(n**0.5) + 1):
            if n % i == 0:
                return False
        return True
    except ValueError:
        return False

prime_number = ri.get_input(
    prompt="Enter a prime number",
    target_type=int,
    custom_validator=is_prime,
    error_message="Please enter a prime number"
)

# Multiple validation layers
user_id = ri.get_input(
    prompt="Enter user ID",
    target_type=int,
    min_length=1,
    max_length=10,
    custom_validator=lambda x: int(x) > 0,
    error_message="User ID must be a positive integer"
)

Styling and Appearance

import robust_input as ri

# Styled prompts and errors
styled_input = ri.get_input(
    prompt="Enter something special",
    prompt_style=[ri.InputStyle.BLUE, ri.InputStyle.BOLD],
    input_style=[ri.InputStyle.CYAN],
    error_style=[ri.InputStyle.RED, ri.InputStyle.BOLD],
    error_message="❌ Invalid input! Please try again."
)

# Colorful interactive menu
menu_choice = ri.get_input(
    prompt="🎮 Choose your action",
    choices=["start", "quit", "help"],
    default="start",
    prompt_style=[ri.InputStyle.GREEN, ri.InputStyle.BOLD],
    input_style=[ri.InputStyle.YELLOW],
    error_message="⚠️ Please choose 'start', 'quit', or 'help'"
)

Convenience Functions

import robust_input as ri

# Integer input with range validation
age = ri.get_integer(
    prompt="Enter your age",
    min_value=1,
    max_value=120,
    error_message="Age must be between 1 and 120"
)

# Choice from predefined options
color = ri.get_choice(
    prompt="Select your favorite color",
    choices=["red", "green", "blue", "yellow"],
    default="blue"
)

# IP address validation
ip_address = ri.get_ip_address(
    prompt="Enter server IP",
    default="192.168.1.1"
)

# Password with built-in masking
password = ri.get_password(
    prompt="Enter password",
    min_length=8,
    error_message="Password must be at least 8 characters"
)

Error Handling and User Experience

import robust_input as ri

# The input function handles all error display and cursor positioning
try:
    # This will show errors below the input line, then reposition cursor
    number = ri.get_input(
        prompt="Enter an even number",
        target_type=int,
        custom_validator=lambda x: int(x) % 2 == 0,
        error_message="❌ Must be an even number!",
        allow_empty=False
    )
    print(f"✅ You entered: {number}")
    
except KeyboardInterrupt:
    print("\n👋 Goodbye!")
except Exception as e:
    print(f"❌ An error occurred: {e}")

API Reference

Main Function

get_input(prompt, **kwargs) -> Any

The primary function for collecting user input with comprehensive validation and styling.

Parameters:

  • prompt (str): The prompt text to display to the user
  • default (Optional[str]): Default value if user presses Enter without input
  • min_length (Optional[int]): Minimum required length for input
  • max_length (Optional[int]): Maximum allowed length for input
  • allow_empty (bool): Whether to allow empty input (default: True)
  • target_type (Type): Type to cast the input to (default: str)
  • pattern (Optional[str]): Regular expression pattern for validation
  • choices (Optional[List[str]]): List of allowed input values
  • is_password (bool): Whether to mask input with asterisks (default: False)
  • prompt_style (Optional[List[str]]): ANSI styles for the prompt
  • input_style (Optional[List[str]]): ANSI styles for user input
  • error_message (Optional[str]): Custom error message for validation failures
  • error_style (Optional[List[str]]): ANSI styles for error messages
  • custom_validator (Optional[Callable[[str], bool]]): Custom validation function

Returns: The validated and type-cast input value

Raises:

  • ValueError: When validation fails (including default values)
  • KeyboardInterrupt: When user presses Ctrl+C

Convenience Functions

get_password(prompt, **kwargs) -> str

Collects password input with asterisk masking.

get_integer(prompt, min_value=None, max_value=None, **kwargs) -> int

Collects integer input with optional range validation.

get_choice(prompt, choices, **kwargs) -> str

Collects input from a predefined list of choices.

get_ip_address(prompt, **kwargs) -> str

Collects and validates IPv4 address input.

Styling Classes

InputStyle

Provides ANSI color codes and text styles:

# Colors
InputStyle.BLACK, InputStyle.RED, InputStyle.GREEN, InputStyle.YELLOW
InputStyle.BLUE, InputStyle.MAGENTA, InputStyle.CYAN, InputStyle.WHITE

# Text Styles
InputStyle.BOLD, InputStyle.UNDERLINE, InputStyle.RESET

InputValidator

Static methods for validation:

  • validate_length(value, min_len, max_len) -> bool
  • validate_type(value, target_type) -> bool
  • validate_pattern(value, pattern) -> bool
  • validate_ip_address(value) -> bool
  • validate_in_choices(value, choices) -> bool

Architecture

The module uses a clean architecture with separated concerns:

  • InputHandler: Manages terminal interaction and character processing
  • InputConfig: Encapsulates all configuration parameters
  • InputValidator: Handles all validation logic
  • InputStyle: Provides styling capabilities

User Experience Features

Smart Error Display

  • Errors appear below the input line
  • Error messages persist until next validation
  • No screen scrolling or clutter
  • Instant feedback without delays

Terminal Control

  • Character-by-character input processing
  • Full cursor movement support (left/right arrows)
  • Proper backspace handling
  • Terminal state restoration

Cross-Platform Support

  • Terminal mode: Full features with ANSI escape sequences
  • Non-terminal mode: Graceful fallback using standard input()
  • Automatic detection: Seamlessly switches between modes

Complete Examples

See the examples/ directory for comprehensive usage demonstrations.

Quick Example

#!/usr/bin/env python3
"""Quick example demonstrating robust_input features."""

import robust_input as ri

def main():
    # Basic input with validation
    name = ri.get_input(
        prompt="Enter your name",
        min_length=2,
        max_length=50,
        error_message="Name must be 2-50 characters"
    )
    
    # Integer input with range validation
    age = ri.get_integer(
        prompt="Enter your age",
        min_value=13,
        max_value=120,
        error_message="Age must be between 13 and 120"
    )
    
    # Choice selection with styling
    theme = ri.get_choice(
        prompt="Choose theme",
        choices=["light", "dark", "auto"],
        default="auto",
        prompt_style=[ri.InputStyle.CYAN, ri.InputStyle.BOLD]
    )
    
    print(f"\nHello {name} (age {age}), using {theme} theme!")

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\nGoodbye!")

Development

Architecture Highlights

  • Low Cognitive Complexity: Refactored from 700% complexity to manageable levels
  • Separated Concerns: Each class handles a specific responsibility
  • Comprehensive Testing: Extensive validation and error handling
  • Professional UX: Terminal-grade user experience

Code Quality

  • Type hints throughout
  • Comprehensive docstrings
  • Clean error handling
  • Proper resource management
  • Cross-platform compatibility

Documentation

For comprehensive documentation, see the docs/ directory:

Testing

The library includes a comprehensive test suite with 69% coverage:

# Run tests
make test

# Generate coverage report  
make coverage

# Run tests with verbose output
make test-verbose

Test Coverage Summary:

  • 53 tests across all components
  • Unit, integration, and mock testing strategies
  • Comprehensive validation and error handling tests
  • CI/CD integration with GitHub Actions

Development

Development Setup

# Clone repository
git clone <repository-url>
cd robust_input

# Setup environment
python -m venv venv
source venv/bin/activate
pip install coverage black isort flake8

# Verify setup
make validate
make test

Development Commands

  • make test - Run all tests
  • make coverage - Generate coverage report
  • make lint - Check code quality
  • make format - Auto-format code
  • make clean - Clean generated files

Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make changes with tests
  4. Ensure all tests pass (make test)
  5. Submit a pull request

See Developer Guide for detailed contribution guidelines.

License

This project is open source and available under the MIT License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

robust_input-1.0.0.tar.gz (15.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

robust_input-1.0.0-py3-none-any.whl (15.1 kB view details)

Uploaded Python 3

File details

Details for the file robust_input-1.0.0.tar.gz.

File metadata

  • Download URL: robust_input-1.0.0.tar.gz
  • Upload date:
  • Size: 15.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for robust_input-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3a22b9dbbfeac7e6c932decaa4356163078c9bb0b476377f75afdb7b44470729
MD5 da85772114086c7356ceff3f244d5616
BLAKE2b-256 99112cefa58fcb62234cffe106eebcbf9fd61c0183be59bc1ddd9227128f9e15

See more details on using hashes here.

File details

Details for the file robust_input-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: robust_input-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 15.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for robust_input-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 415ef85f4ffcf83ec975f176f16f95659e7d57e2d37536602307e0ec7f4d6116
MD5 4d5741545e329529321ad6566eab38c7
BLAKE2b-256 6dbc15cc7dbfdff5d9e46e760643bde51955ef18206aa956814e18a73a6dd982

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page