User Input Prompting
The prompt module in Valid8r provides tools for interactively prompting users for input with built-in validation. This is particularly useful for command-line applications.
Basic Usage
from valid8r import prompt, parsers, validators
from valid8r.core.maybe import Success, Failure
# Ask for a simple string
name = prompt.ask("Enter your name: ")
match name:
case Success(value):
print(f"Hello, {value}!")
case Failure(error):
print(f"Error: {error}")
# Ask for an integer
age = prompt.ask(
"Enter your age: ",
parser=parsers.parse_int
)
match age:
case Success(value):
print(f"You are {value} years old.")
case Failure(error):
print(f"Error: {error}")
# Ask for a validated value
score = prompt.ask(
"Enter a score (0-100): ",
parser=parsers.parse_int,
validator=validators.between(0, 100)
)
match score:
case Success(value):
print(f"Score: {value}")
case Failure(error):
print(f"Error: {error}")
The ask Function
The ask function is the main entry point for user input prompting:
def ask(
prompt_text: str,
parser: Callable[[str], Maybe[T]] = None,
validator: Callable[[T], Maybe[T]] = None,
error_message: str = None,
default: T = None,
retry: bool | int = False,
) -> Maybe[T]:
"""Prompt the user for input with validation."""
Parameters:
prompt_text: The text to display to the user
parser: A function to convert the string input to the desired type (defaults to identity function)
validator: A function to validate the parsed value (defaults to always valid)
error_message: Custom error message for invalid input
default: Default value to use if the user provides empty input
retry: If True, retry indefinitely on invalid input; if an integer, retry that many times
Return Value:
A Maybe containing either the validated value (Success) or an error (Failure)
Default Values
You can provide a default value that will be used if the user enters nothing:
from valid8r import prompt, parsers
from valid8r.core.maybe import Success, Failure
# With a default value
age = prompt.ask(
"Enter your age: ",
parser=parsers.parse_int,
default=30
)
# The prompt will show the default: "Enter your age: [30]: "
# If the user presses Enter without typing anything:
match age:
case Success(value):
print(f"Using age: {value}") # Will be 30 if user pressed Enter
case Failure(error):
print(f"Error: {error}")
Error Handling and Retries
By default, if the user enters invalid input, ask will return a Failure with an error message. You can enable retries to keep asking until valid input is provided:
from valid8r import prompt, parsers, validators
from valid8r.core.maybe import Success, Failure
# No retry (default)
age = prompt.ask(
"Enter your age (0-120): ",
parser=parsers.parse_int,
validator=validators.between(0, 120)
)
# If user enters "abc" or -5, a Failure is returned
match age:
case Success(value):
print(f"Age: {value}")
case Failure(error):
print(f"Invalid input: {error}")
# Infinite retries
age = prompt.ask(
"Enter your age (0-120): ",
parser=parsers.parse_int,
validator=validators.between(0, 120),
retry=True # Keep asking until valid input
)
# This will always return Success if it returns at all
match age:
case Success(value):
print(f"Age: {value}")
case Failure(_):
print("This won't happen unless interrupted")
# Limited retries
age = prompt.ask(
"Enter your age (0-120): ",
parser=parsers.parse_int,
validator=validators.between(0, 120),
retry=3 # Allow 3 attempts
)
# If valid input is provided within 3 attempts, Success is returned
# Otherwise, Failure is returned
match age:
case Success(value):
print(f"Age: {value}")
case Failure(error):
print(f"Failed after maximum retries: {error}")
When retry is enabled, error messages are displayed to the user:
Enter your age (0-120): abc
Error: Input must be a valid integer
Enter your age (0-120): -5
Error: Value must be between 0 and 120
Enter your age (0-120): 42
# Valid input, function returns Success(42)
Custom Error Messages
You can provide a custom error message that overrides the default ones:
from valid8r import prompt, parsers
from valid8r.core.maybe import Success, Failure
age = prompt.ask(
"Enter your age: ",
parser=parsers.parse_int,
error_message="Please enter a valid age as a positive number",
retry=True
)
# If user enters "abc":
# Error: Please enter a valid age as a positive number
# The prompt will keep asking with this error message until valid input
Processing User Input
Using pattern matching to process user input results:
from valid8r import prompt, parsers, validators
from valid8r.core.maybe import Success, Failure
def process_age_input():
age = prompt.ask(
"Enter your age: ",
parser=parsers.parse_int,
validator=validators.between(0, 120),
retry=3
)
match age:
case Success(value) if value < 18:
return f"You are {value} years old. You are a minor."
case Success(value) if value >= 65:
return f"You are {value} years old. You are a senior citizen."
case Success(value):
return f"You are {value} years old. You are an adult."
case Failure(error):
return f"Could not process age: {error}"
result = process_age_input()
print(result)
Common Patterns
Here are some common patterns for using the prompt module:
Password Input
from valid8r import prompt, validators, Maybe
from valid8r.core.maybe import Success, Failure
from getpass import getpass
# Custom parser that uses getpass for hidden input
def password_parser(prompt_text):
password = getpass(prompt_text)
return Maybe.success(password)
# Password validation
password_validator = validators.length(8, 64) & validators.predicate(
lambda p: any(c.isupper() for c in p) and any(c.isdigit() for c in p),
"Password must contain at least one uppercase letter and one digit"
)
password = prompt.ask(
"Enter password: ",
parser=lambda _: password_parser("Password: "),
validator=password_validator,
retry=True
)
match password:
case Success(value):
print(f"Password accepted: {'*' * len(value)}")
case Failure(error):
print(f"Password error: {error}")
Confirmation Prompts
from valid8r import prompt, parsers
from valid8r.core.maybe import Success, Failure
# Ask for confirmation
confirm = prompt.ask(
"Are you sure? (y/n): ",
parser=parsers.parse_bool,
retry=True
)
match confirm:
case Success(value) if value:
print("Proceeding...")
case Success(_):
print("Operation cancelled.")
case Failure(error):
print(f"Error: {error}")
Interactive Applications
The prompt module is ideal for building interactive command-line applications:
from valid8r import prompt, parsers, validators
from valid8r.core.maybe import Success, Failure
import sys
def main():
print("Contact Manager")
print("===============")
while True:
print("\nOptions:")
print("1. Add contact")
print("2. View contacts")
print("3. Exit")
choice = prompt.ask(
"Enter choice (1-3): ",
parser=parsers.parse_int,
validator=validators.between(1, 3),
retry=True
)
match choice:
case Success(1):
add_contact()
case Success(2):
view_contacts()
case Success(3):
print("Goodbye!")
sys.exit(0)
case Failure(error):
print(f"Error: {error}")
continue
def add_contact():
# Implementation using prompt.ask
name = prompt.ask("Enter name: ", retry=True)
phone = prompt.ask("Enter phone: ", retry=True)
match (name, phone):
case (Success(name_val), Success(phone_val)):
print(f"Added contact: {name_val}, {phone_val}")
case (Failure(error), _):
print(f"Name error: {error}")
case (_, Failure(error)):
print(f"Phone error: {error}")
def view_contacts():
# Implementation
print("No contacts available")
if __name__ == "__main__":
main()
Best Practices
Provide clear prompt text: Make sure the user knows what kind of input is expected
Include validation requirements: For example, “Enter your age (0-120): “
Use appropriate parsers: Match the parser to the expected input type
Enable retries for better UX: Especially in interactive applications
Provide helpful error messages: Explain what went wrong and how to fix it
Use default values where appropriate: Makes input quicker for common cases
Handle all result cases: Always use pattern matching to handle both Success and Failure cases
Limitations
Terminal-based only: The prompt module is designed for command-line interfaces
No input masking: For sensitive input like passwords, use
getpassmoduleNo colored output: Error messages are displayed in plain text
No interactive features: No arrow key navigation, autocomplete, etc.
In the next section, we’ll explore advanced usage patterns and more complex examples.