valid8r.prompt

Input prompting functionality for command-line applications.

This module provides interactive prompting with validation, parsing, and pluggable I/O providers for testing and alternative UIs.

Submodules

Classes

BuiltinIOProvider

Default IO provider using Python builtins (input/print).

IOProvider

Protocol for pluggable input/output in prompt functions.

TestIOProvider

IO provider for testing that captures I/O without builtins.

Functions

ask(prompt_text, *[, parser, validator, ...])

Prompt the user for input with parsing and validation.

Package Contents

valid8r.prompt.ask(prompt_text, *, parser=None, validator=None, error_message=None, default=None, retry=False, io_provider=None, _test_mode=False)[source]

Prompt the user for input with parsing and validation.

Displays a prompt to the user, parses their input using the provided parser, validates the result, and optionally retries on failure. Returns a Maybe monad containing either the validated input or an error message.

Parameters:
  • prompt_text (str) – The prompt message to display to the user

  • parser (collections.abc.Callable[[str], valid8r.core.maybe.Maybe[T]] | None) – Function to convert string input to desired type (default: returns string as-is)

  • validator (collections.abc.Callable[[T], valid8r.core.maybe.Maybe[T]] | None) – Function to validate the parsed value (default: accepts any value)

  • error_message (str | None) – Custom error message to display on validation failure

  • default (T | None) – Default value to use if user provides empty input (displays in prompt)

  • retry (bool | int) – Enable retry on failure - True for unlimited, integer for max attempts, False to disable

  • io_provider (valid8r.prompt.io_provider.IOProvider | None) – IO provider for handling input/output (default: BuiltinIOProvider)

  • _test_mode (bool) – Internal testing parameter (do not use)

Returns:

Success with validated input, or Failure with error message

Return type:

Maybe[T]

Examples

Basic integer input with validation:

from valid8r.core import parsers, validators
from valid8r.prompt import ask

result = ask(
    "Enter your age: ",
    parser=parsers.parse_int,
    validator=validators.between(0, 120),
    retry=True
)
# User enters "25" -> Success(25)
# User enters "invalid" -> prompts again with error message

Input with default value:

result = ask(
    "Enter port: ",
    parser=parsers.parse_int,
    default=8080
)
# User presses Enter -> Success(8080)
# User enters "3000" -> Success(3000)

Limited retries with custom error:

result = ask(
    "Email: ",
    parser=parsers.parse_email,
    error_message="Invalid email format",
    retry=3
)
# User has 3 attempts to enter valid email

Boolean input with retry:

result = ask(
    "Continue? (yes/no): ",
    parser=parsers.parse_bool,
    retry=True
)
# User enters "yes" -> Success(True)
# User enters "maybe" -> error, retry prompt

Note

The returned Maybe must be unwrapped to access the value. Use pattern matching or .value_or() to extract the result.

class valid8r.prompt.BuiltinIOProvider[source]

Default IO provider using Python builtins (input/print).

This provider delegates to Python’s built-in input() and print() functions, providing standard command-line interaction behavior.

Examples:

from valid8r.prompt.io_provider import BuiltinIOProvider
provider = BuiltinIOProvider()

# Input from user
user_input = provider.input("Name: ")  # Uses input()

# Output to console
provider.output("Hello!")  # Uses print()

# Error to console
provider.error("Invalid input")  # Uses print()
input(prompt)[source]

Display prompt using builtins.input.

Parameters:

prompt (str) – The prompt message to display

Returns:

The user’s input string

Return type:

str

output(message)[source]

Display output using builtins.print.

Parameters:

message (str) – The message to display

Return type:

None

error(message)[source]

Display error using builtins.print.

Parameters:

message (str) – The error message to display

Return type:

None

class valid8r.prompt.IOProvider[source]

Bases: Protocol

Protocol for pluggable input/output in prompt functions.

Implementations of this protocol can provide custom behavior for displaying prompts, collecting input, and showing error messages. This enables testing without mocking builtins and supports alternative UIs beyond command-line interfaces.

Examples

Use default builtin provider:

from valid8r.prompt.io_provider import BuiltinIOProvider
from valid8r.prompt.basic import ask
from valid8r.core.parsers import parse_int

provider = BuiltinIOProvider()
result = ask("Age: ", parser=parse_int, io_provider=provider)

Use test provider for non-interactive testing:

from valid8r.prompt.io_provider import TestIOProvider

test_provider = TestIOProvider(inputs=["25"])
result = ask("Age: ", parser=parse_int, io_provider=test_provider)
# result.value_or(0) == 25
# test_provider.outputs == []
# test_provider.errors == []
input(prompt)[source]

Display prompt and get user input.

Parameters:

prompt (str) – The prompt message to display to the user

Returns:

The user’s input as a string

Return type:

str

output(message)[source]

Display an output message to the user.

Parameters:

message (str) – The message to display

Return type:

None

error(message)[source]

Display an error message to the user.

Parameters:

message (str) – The error message to display

Return type:

None

class valid8r.prompt.TestIOProvider(inputs)[source]

IO provider for testing that captures I/O without builtins.

This provider allows testing prompt functions without monkeypatching builtins.input and builtins.print. It provides pre-configured inputs and captures all outputs and errors for inspection.

Parameters:

inputs (list[str])

inputs

List of input strings to return (consumed in order)

outputs

List of captured output messages

errors

List of captured error messages

Examples

>>> from valid8r.prompt.io_provider import TestIOProvider
>>> from valid8r.prompt.basic import ask
>>> from valid8r.core.parsers import parse_int
>>>
>>> # Set up test provider with simulated inputs
>>> provider = TestIOProvider(inputs=["42", "invalid", "25"])
>>>
>>> # First call returns "42"
>>> result1 = ask("Age: ", parser=parse_int, io_provider=provider)
>>> # result1.value_or(0) == 42
>>>
>>> # Second call with retry consumes "invalid" then "25"
>>> result2 = ask("Age: ", parser=parse_int, retry=1, io_provider=provider)
>>> # result2.value_or(0) == 25
>>>
>>> # Inspect captured output
>>> len(provider.errors)  # 1 error for "invalid"
1
>>> len(provider.outputs)  # No outputs
0
inputs
outputs: list[str] = []
errors: list[str] = []
input(prompt)[source]

Return next simulated input.

Parameters:

prompt (str) – The prompt message (ignored but required by protocol)

Returns:

Next input from the inputs list

Return type:

str

Raises:

RuntimeError – If all inputs have been consumed

output(message)[source]

Capture output message.

Parameters:

message (str) – The output message to capture

Return type:

None

error(message)[source]

Capture error message.

Parameters:

message (str) – The error message to capture

Return type:

None