valid8r.core.maybe

Maybe monad for clean error handling using Success and Failure types.

Attributes

T

U

Exceptions

UnwrapError

Exception raised when unwrap() or expect() is called on Failure, or unwrap_err() on Success.

Classes

Maybe

Base class for the Maybe monad.

Success

Represents a successful computation with a value.

Failure

Represents a failed computation with an error message or ValidationError.

Module Contents

valid8r.core.maybe.T[source]
valid8r.core.maybe.U[source]
exception valid8r.core.maybe.UnwrapError[source]

Bases: ValueError

Exception raised when unwrap() or expect() is called on Failure, or unwrap_err() on Success.

This exception provides type-safe value extraction from Maybe types. When users need to extract a value and are certain the operation succeeded, they can use unwrap() or expect() which will raise this exception on failure.

Inherits from ValueError since the error represents an invalid operation on a value (attempting to extract from wrong state).

Examples

Using unwrap() on Failure:

>>> result = Maybe.failure('validation error')
>>> try:
...     result.unwrap()
... except UnwrapError as e:
...     print(f'Error: {e}')
Error: Called unwrap() on Failure: validation error

Using expect() with custom message:

>>> result = Maybe.failure('internal error')
>>> try:
...     result.expect('User ID is required')
... except UnwrapError as e:
...     print(f'Error: {e}')
Error: User ID is required
class valid8r.core.maybe.Maybe[source]

Bases: abc.ABC, Generic[T]

Base class for the Maybe monad.

static success(value)[source]

Create a Success containing a value.

Parameters:

value (T)

Return type:

Success[T]

static failure(error)[source]

Create a Failure containing an error message or ValidationError.

Parameters:

error (str | valid8r.core.errors.ValidationError) – Error message string or ValidationError instance

Returns:

Failure instance with the error

Return type:

Failure[T]

abstractmethod is_success()[source]

Check if the Maybe is a Success.

Return type:

bool

abstractmethod is_failure()[source]

Check if the Maybe is a Failure.

Return type:

bool

abstractmethod bind(f)[source]

Chain operations that might fail.

Parameters:

f (collections.abc.Callable[[T], Maybe[U]])

Return type:

Maybe[U]

abstractmethod and_then(f)[source]

Chain operations that might fail. Python-friendly alias for bind().

This method is functionally identical to bind() but uses naming more familiar to Python developers. Use whichever name fits your style.

Parameters:

f (collections.abc.Callable[[T], Maybe[U]]) – Function that takes a value and returns Maybe[U]

Returns:

Result of applying f to the value if Success,

or propagated Failure if already failed

Return type:

Maybe[U]

Examples

Chain operations using and_then:

>>> result = Maybe.success(5).and_then(lambda x: Maybe.success(x * 2))
>>> result.value_or(0)
10

Propagates failure:

>>> result = Maybe.failure('error').and_then(lambda x: Maybe.success(x * 2))
>>> result.is_failure()
True
abstractmethod bind_async(f)[source]
Async:

Parameters:

f (collections.abc.Callable[[T], collections.abc.Awaitable[Maybe[U]]])

Return type:

Maybe[U]

Async version of bind for composing async validators.

This method enables chaining async operations that might fail, similar to bind() but for async functions.

Parameters:

f (collections.abc.Callable[[T], collections.abc.Awaitable[Maybe[U]]]) – Async function that takes a value and returns Maybe[U]

Returns:

Result of applying f to the value if Success,

or propagated Failure if already failed

Return type:

Maybe[U]

Examples

Async validation:

>>> import asyncio
>>> async def async_double(x: int) -> Maybe[int]:
...     await asyncio.sleep(0.001)
...     return Maybe.success(x * 2)
>>> result = asyncio.run(Maybe.success(21).bind_async(async_double))
>>> result.value_or(None)
42

Chaining async validators:

>>> async def async_validator(x: int) -> Maybe[int]:
...     await asyncio.sleep(0.001)
...     if x < 0:
...         return Maybe.failure('must be non-negative')
...     return Maybe.success(x)
>>> result = asyncio.run(Maybe.success(-5).bind_async(async_validator))
>>> result.is_failure()
True
abstractmethod map(f)[source]

Transform the value if present.

Parameters:

f (collections.abc.Callable[[T], U])

Return type:

Maybe[U]

abstractmethod value_or(default)[source]

Return the contained value or the provided default if this is a Failure.

Parameters:

default (T)

Return type:

T

abstractmethod error_or(default)[source]

Return the error message or the provided default if this is a Success.

Parameters:

default (str)

Return type:

str

abstractmethod get_error()[source]

Get the error message if present, otherwise None.

Return type:

str | None

abstractmethod unwrap()[source]

Extract value or raise UnwrapError if Failure.

This method provides type-safe value extraction when you’re confident the Maybe is a Success. Unlike value_or(), it doesn’t require a default value and the return type is T (not T | default_type).

Returns:

The contained value of type T

Raises:

UnwrapError – If called on a Failure

Return type:

T

Examples

Safe extraction after validation:

>>> result = Maybe.success(42)
>>> result.unwrap()
42

Raises on Failure:

>>> result = Maybe.failure('invalid input')
>>> result.unwrap()
Traceback (most recent call last):
    ...
UnwrapError: Called unwrap() on Failure: invalid input
abstractmethod expect(msg)[source]

Extract value or raise UnwrapError with custom message if Failure.

Similar to unwrap(), but allows providing a custom error message that is more meaningful in the context where the extraction happens.

Parameters:

msg (str) – Custom error message to use if this is a Failure

Returns:

The contained value of type T

Raises:

UnwrapError – If called on a Failure, with the custom message

Return type:

T

Examples

With meaningful context:

>>> result = Maybe.success(42)
>>> result.expect('User age is required')
42

Custom error message on failure:

>>> result = Maybe.failure('parse error')
>>> result.expect('Failed to load user profile')
Traceback (most recent call last):
    ...
UnwrapError: Failed to load user profile
abstractmethod unwrap_err()[source]

Extract error message or raise UnwrapError if Success.

This method provides type-safe error extraction when you’re confident the Maybe is a Failure. Useful in error handling code paths.

Returns:

The error message string

Raises:

UnwrapError – If called on a Success

Return type:

str

Examples

Extract error for logging:

>>> result = Maybe.failure('validation failed')
>>> result.unwrap_err()
'validation failed'

Raises on Success:

>>> result = Maybe.success(42)
>>> result.unwrap_err()
Traceback (most recent call last):
    ...
UnwrapError: Called unwrap_err() on Success
abstractmethod to_optional()[source]

Convert Maybe to an optional value.

Returns the contained value if Success, or None if Failure. This is useful for interoperability with code that uses Optional[T].

Returns:

The contained value if Success, None if Failure

Return type:

T | None

Examples

Convert Success to optional:

>>> result = Maybe.success(42)
>>> result.to_optional()
42

Convert Failure to optional:

>>> result = Maybe.failure('error')
>>> result.to_optional() is None
True
static from_optional(value, error_msg='Value was None')[source]

Convert an optional value to Maybe.

Returns Success(value) if value is not None, otherwise Failure with the provided error message. This is useful for interoperability with code that uses Optional[T].

Note: This method distinguishes only None from non-None values. Falsy values like 0, ‘’, [], and False are treated as valid values and wrapped in Success.

Parameters:
  • value (T | None) – The optional value to convert

  • error_msg (str) – Error message to use if value is None (default: ‘Value was None’)

Returns:

Success(value) if value is not None, Failure(error_msg) otherwise

Return type:

Maybe[T]

Examples

Convert non-None value:

>>> result = Maybe.from_optional(42)
>>> result.value_or(0)
42

Convert None value:

>>> result = Maybe.from_optional(None)
>>> result.is_failure()
True

Custom error message:

>>> result = Maybe.from_optional(None, error_msg='User ID is required')
>>> result.error_or('')
'User ID is required'

Falsy values are valid:

>>> Maybe.from_optional(0).value_or(-1)
0
>>> Maybe.from_optional('').value_or('default')
''
class valid8r.core.maybe.Success(value)[source]

Bases: Maybe[T]

Represents a successful computation with a value.

Parameters:

value (T)

__match_args__ = ('value',)[source]
value[source]
is_success()[source]

Check if the Maybe is a Success.

Return type:

bool

is_failure()[source]

Check if the Maybe is a Failure.

Return type:

bool

bind(f)[source]

Chain operations that might fail.

Parameters:

f (collections.abc.Callable[[T], Maybe[U]])

Return type:

Maybe[U]

and_then(f)[source]

Chain operations that might fail. Python-friendly alias for bind().

Parameters:

f (collections.abc.Callable[[T], Maybe[U]])

Return type:

Maybe[U]

async bind_async(f)[source]

Async version of bind for composing async validators.

Parameters:

f (collections.abc.Callable[[T], collections.abc.Awaitable[Maybe[U]]])

Return type:

Maybe[U]

map(f)[source]

Transform the value.

Parameters:

f (collections.abc.Callable[[T], U])

Return type:

Maybe[U]

value_or(_default)[source]

Return the contained value (default is ignored for Success).

Parameters:

_default (T)

Return type:

T

error_or(default)[source]

Return the provided default since Success has no error.

Parameters:

default (str)

Return type:

str

get_error()[source]

Get None since Success has no error.

Return type:

str | None

unwrap()[source]

Extract the contained value.

For Success, always returns the contained value.

Return type:

T

expect(_msg)[source]

Extract the contained value, ignoring the message.

For Success, always returns the contained value. The message parameter is ignored since extraction always succeeds.

Parameters:

_msg (str)

Return type:

T

unwrap_err()[source]

Raise UnwrapError since Success has no error.

Raises:

UnwrapError – Always, since Success doesn’t contain an error

Return type:

str

to_optional()[source]

Return the contained value.

For Success, always returns the contained value.

Return type:

T | None

__str__()[source]

Get a string representation.

Return type:

str

__repr__()[source]

Get a repr representation for debugging and doctests.

Return type:

str

class valid8r.core.maybe.Failure(error)[source]

Bases: Maybe[T]

Represents a failed computation with an error message or ValidationError.

Failure now accepts both string error messages (backward compatible) and ValidationError instances (new structured error support).

When a string is provided, it’s automatically wrapped in a ValidationError with code=’VALIDATION_ERROR’ for consistent internal handling.

Examples

Backward compatible string error:

>>> failure = Failure('Something went wrong')
>>> failure.error_or('')
'Something went wrong'

New structured error:

>>> from valid8r.core.errors import ValidationError, ErrorCode
>>> error = ValidationError(code=ErrorCode.INVALID_EMAIL, message='Bad email')
>>> failure = Failure(error)
>>> failure.validation_error.code
'INVALID_EMAIL'
Parameters:

error (str | valid8r.core.errors.ValidationError)

__match_args__ = ('error',)[source]
property error: str[source]

Get the error message string (backward compatible for pattern matching).

This property returns the message string to maintain backward compatibility with existing pattern matching code: case Failure(error): assert error == "message"

For structured error access, use the validation_error property instead.

Returns:

Error message string

Return type:

str

property validation_error: valid8r.core.errors.ValidationError[source]

Get the structured ValidationError instance.

Use this property to access the full structured error with code, path, and context.

Returns:

ValidationError instance

Return type:

valid8r.core.errors.ValidationError

Examples

>>> from valid8r.core.errors import ValidationError, ErrorCode
>>> error = ValidationError(code=ErrorCode.INVALID_EMAIL, message='Bad email', path='.email')
>>> failure = Failure(error)
>>> failure.validation_error.code
'INVALID_EMAIL'
>>> failure.validation_error.path
'.email'
error_detail()[source]

Get the structured ValidationError instance (RFC-001 Phase 2).

This method provides access to the full structured error with code, path, and context. It returns the same object as the validation_error property, but follows the RFC-001 specification for the public API.

For backward compatibility, both error_detail() and validation_error property are maintained.

Returns:

ValidationError instance with code, message, path, and context

Return type:

valid8r.core.errors.ValidationError

Examples

Access structured error from string failure:

>>> failure = Failure('Invalid input')
>>> error = failure.error_detail()
>>> error.code
'VALIDATION_ERROR'
>>> error.message
'Invalid input'

Access structured error from ValidationError failure:

>>> from valid8r.core.errors import ValidationError, ErrorCode
>>> error = ValidationError(code=ErrorCode.OUT_OF_RANGE, message='Too high', path='.value')
>>> failure = Failure(error)
>>> detail = failure.error_detail()
>>> detail.code
'OUT_OF_RANGE'
>>> detail.path
'.value'
is_success()[source]

Check if the Maybe is a Success.

Return type:

bool

is_failure()[source]

Check if the Maybe is a Failure.

Return type:

bool

bind(_f)[source]

Chain operations that might fail.

Function is unused in Failure case as we always propagate the error.

Parameters:

_f (collections.abc.Callable[[T], Maybe[U]])

Return type:

Maybe[U]

and_then(_f)[source]

Chain operations that might fail. Python-friendly alias for bind().

Function is unused in Failure case as we always propagate the error.

Parameters:

_f (collections.abc.Callable[[T], Maybe[U]])

Return type:

Maybe[U]

async bind_async(_f)[source]

Async version of bind for composing async validators.

Function is unused in Failure case as we always propagate the error.

Parameters:

_f (collections.abc.Callable[[T], collections.abc.Awaitable[Maybe[U]]])

Return type:

Maybe[U]

map(_f)[source]

Transform the value if present.

Function is unused in Failure case as we always propagate the error.

Parameters:

_f (collections.abc.Callable[[T], U])

Return type:

Maybe[U]

value_or(default)[source]

Return the provided default for Failure.

Parameters:

default (T)

Return type:

T

error_or(default)[source]

Return the error message string (backward compatible).

Returns:

Error message from ValidationError, or default if message is empty

Parameters:

default (str)

Return type:

str

get_error()[source]

Get the error message string (backward compatible).

Returns:

Error message from ValidationError

Return type:

str | None

unwrap()[source]

Raise UnwrapError since Failure has no value.

Raises:

UnwrapError – Always, with the error message from this Failure

Return type:

T

expect(msg)[source]

Raise UnwrapError with custom message.

Parameters:

msg (str) – Custom error message to include in the exception

Raises:

UnwrapError – Always, with the custom message

Return type:

T

unwrap_err()[source]

Extract the error message.

For Failure, always returns the error message string.

Return type:

str

to_optional()[source]

Return None since Failure has no value.

For Failure, always returns None.

Return type:

T | None

__str__()[source]

Get a string representation.

Returns:

String showing error message (backward compatible format)

Return type:

str

__repr__()[source]

Get a repr representation for debugging and doctests.

Returns:

String showing error message (backward compatible format)

Return type:

str