ddp_utils.validation

import ddp_utils.validation

Provide composable validators with structured validation results.

Validators collect rules through a fluent API and normally return ValidationResult instead of raising. Use Validator.validate_or_raise() when an exception-based boundary is preferable.

Examples

Validate an email address and inspect the structured result:

from ddp_utils.validation import v

result = v.string("hello@example.com").min(5).email().validate()
if not result.ok:
    print(result.errors)
class ddp_utils.validation.ValidationResult(ok: bool, errors: List[str] = <factory>, value: Any = None)

Bases: object

Describe validation of one value.

Parameters

Name

Type

Description

ok

bool

Whether every configured rule passed.

errors

List[str]

Error messages returned by failed rules.

value

Any

The validated value.

Examples

Create a successful result:

result = ValidationResult(ok=True, value="ready")
assert result
first_error() → str | None

Return the first recorded error message.

Returns

Type

Description

str | None

The first error string, or None when no error was recorded.

Examples

Read the primary failure reason:

result = ValidationResult(False, ["value: required"])
assert result.first_error() == "value: required"
class ddp_utils.validation.BatchValidationResult(ok: bool, field_errors: Dict[str, ~typing.List[str]]=<factory>)

Bases: object

Describe validation results grouped by dictionary field.

Parameters

Name

Type

Description

ok

bool

Whether every field validator passed.

field_errors

Dict[str, List[str]]

Mapping of field names to their validation errors.

Examples

Represent one invalid field:

result = BatchValidationResult(False, {"age": ["min 18, got 16"]})
assert not result
flat_errors() → List[str]

Flatten field errors into prefixed strings.

Returns

Type

Description

List[str]

Error strings formatted as "field: message" in mapping order.

Examples

Prepare field errors for display:

result = BatchValidationResult(False, {"age": ["required"]})
assert result.flat_errors() == ["age: required"]
class ddp_utils.validation.Validator(value: Any = None)

Bases: object

Collect and execute validation rules for a value.

Prefer the typed factories exposed by v for strings, numbers, booleans, and lists.

Parameters

Name

Type

Description

value

Any

Optional value stored for a later validate() call.

Examples

Add a custom rule to the base validator:

validator = Validator("ABC").custom(
    lambda value: None if value.isupper() else "must be uppercase"
)
assert validator.validate().ok

Initialize a validator without rules.

Parameters

Name

Type

Description

value

Any

Optional value stored for validation. A non-None value passed to validate() takes precedence.

Examples

Store a value and add a custom rule later:

validator = Validator("value")
label(name: str) → Validator

Set the field label used by the required-value error.

Parameters

Name

Type

Description

name

str

Human-readable field label.

Returns

Type

Description

Validator

This validator, allowing fluent rule construction.

Examples

Identify a missing value as an email field:

result = Validator().label("email").validate()
assert result.first_error() == "email: required"
optional() → Validator

Accept None or an empty string without evaluating rules.

Returns

Type

Description

Validator

This validator, allowing fluent rule construction.

Examples

Permit an omitted optional value:

assert v.string().optional().email().validate(None).ok
custom(fn: Callable[[Any], str | None]) → Validator

Append a custom validation rule.

Parameters

Name

Type

Description

fn

Callable[[Any], str | None]

Callable returning an error string on failure or None on success.

Returns

Type

Description

Validator

This validator, allowing fluent rule construction.

Examples

Require a string to start with h:

validator = v.string("hello").custom(
    lambda value: None if value.startswith("h") else "must start with h"
)
validate(value: Any = None) → ValidationResult

Evaluate every configured rule against a value.

Parameters

Name

Type

Description

value

Any

Value to validate. None selects the value stored at construction time.

Returns

Type

Description

ValidationResult

A result containing the selected value and all rule errors.

Examples

Validate a value supplied after rule construction:

result = v.string().min(3).validate("abc")
assert result.ok
validate_or_raise(value: Any = None) → Any

Validate a value and raise when any rule fails.

Parameters

Name

Type

Description

value

Any

Value to validate. None selects the stored value.

Returns

Type

Description

Any

The selected value when validation succeeds.

Raises

Exception

Description

ValueError

One or more rules failed. Messages are joined with semicolons.

Examples

Enforce validation at an input boundary:

email = v.string("user@example.com").email().validate_or_raise()
class ddp_utils.validation.StringValidator(value: Any = None)

Bases: Validator

Build rules that inspect string representations of values.

Parameters

Name

Type

Description

value

Any

Optional value stored for later validation.

Examples

Validate the length and format of an email address:

result = StringValidator("user@example.com").min(5).email().validate()

Initialize a validator without rules.

Parameters

Name

Type

Description

value

Any

Optional value stored for validation. A non-None value passed to validate() takes precedence.

Examples

Store a value and add a custom rule later:

validator = Validator("value")
min(length: int) → StringValidator

Require at least length characters.

Parameters

Name

Type

Description

length

int

Inclusive minimum length.

Returns

Type

Description

StringValidator

This validator.

Examples

Require a three-character value:

result = v.string("abc").min(3).validate()
max(length: int) → StringValidator

Allow at most length characters.

Parameters

Name

Type

Description

length

int

Inclusive maximum length.

Returns

Type

Description

StringValidator

This validator.

Examples

Limit a value to ten characters:

result = v.string("short").max(10).validate()
exact(length: int) → StringValidator

Require exactly length characters.

Parameters

Name

Type

Description

length

int

Required character count.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate a two-letter code:

result = v.string("US").exact(2).validate()
email() → StringValidator

Require the value to match the built-in email pattern.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate a conventional email address:

result = v.string("user@example.com").email().validate()
url() → StringValidator

Require an HTTP or HTTPS URL.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate an HTTPS URL:

result = v.string("https://example.com/path").url().validate()
uuid() → StringValidator

Require a canonical hyphenated UUID string.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate a UUID string:

result = v.string("123e4567-e89b-12d3-a456-426614174000").uuid().validate()
pattern(regex: str, message: str | None = None) → StringValidator

Require a regular-expression search match.

Parameters

Name

Type

Description

regex

str

Pattern compiled when the rule is added.

message

str | None

Optional failure message replacing the generated message.

Returns

Type

Description

StringValidator

This validator.

Raises

Exception

Description

re.error

regex is not a valid regular expression.

Examples

Require an uppercase three-letter code:

result = v.string("USA").pattern(r"^[A-Z]{3}$").validate()
not_empty() → StringValidator

Reject values containing only whitespace.

Returns

Type

Description

StringValidator

This validator.

Examples

Reject a whitespace-only string:

result = v.string("   ").not_empty().validate()
assert not result.ok
one_of(choices: List[str], case_sensitive: bool = True) → StringValidator

Require membership in a list of strings.

Parameters

Name

Type

Description

choices

List[str]

Allowed string values.

case_sensitive

bool

Whether comparison preserves character case.

Returns

Type

Description

StringValidator

This validator.

Examples

Match a choice without case sensitivity:

result = v.string("yes").one_of(["YES", "NO"], False).validate()
starts_with(prefix: str) → StringValidator

Require the string representation to start with prefix.

Parameters

Name

Type

Description

prefix

str

Required leading text.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate an identifier prefix:

result = v.string("case-42").starts_with("case-").validate()
ends_with(suffix: str) → StringValidator

Require the string representation to end with suffix.

Parameters

Name

Type

Description

suffix

str

Required trailing text.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate a filename suffix:

result = v.string("report.pdf").ends_with(".pdf").validate()
no_spaces() → StringValidator

Reject literal space characters in the string representation.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate a compact username:

result = v.string("user_name").no_spaces().validate()
alphanumeric() → StringValidator

Require Unicode alphanumeric characters only.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate an alphanumeric identifier:

result = v.string("Case42").alphanumeric().validate()
path_exists() → StringValidator

Require the represented filesystem path to exist.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate the current directory:

result = v.string(".").path_exists().validate()
is_file() → StringValidator

Require the represented filesystem path to be a regular file.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate a configuration file path:

result = v.string("settings.ini").is_file().validate()
is_dir() → StringValidator

Require the represented filesystem path to be a directory.

Returns

Type

Description

StringValidator

This validator.

Examples

Validate the current directory:

result = v.string(".").is_dir().validate()
class ddp_utils.validation.NumberValidator(value: Any = None)

Bases: Validator

Build rules for values coercible to float.

Parameters

Name

Type

Description

value

Any

Optional value stored for later validation.

Examples

Validate an integer inside an inclusive range:

result = NumberValidator(42).between(0, 100).integer().validate()

Initialize a validator without rules.

Parameters

Name

Type

Description

value

Any

Optional value stored for validation. A non-None value passed to validate() takes precedence.

Examples

Store a value and add a custom rule later:

validator = Validator("value")
min(minimum: int | float) → NumberValidator

Require a numeric value greater than or equal to minimum.

Parameters

Name

Type

Description

minimum

int | float

Inclusive lower bound.

Returns

Type

Description

NumberValidator

This validator.

Examples

Reject values below zero:

result = v.number(10).min(0).validate()
max(maximum: int | float) → NumberValidator

Require a numeric value less than or equal to maximum.

Parameters

Name

Type

Description

maximum

int | float

Inclusive upper bound.

Returns

Type

Description

NumberValidator

This validator.

Examples

Limit a percentage to one hundred:

result = v.number(85).max(100).validate()
between(minimum: int | float, maximum: int | float) → NumberValidator

Require a numeric value inside an inclusive range.

Parameters

Name

Type

Description

minimum

int | float

Inclusive lower bound.

maximum

int | float

Inclusive upper bound.

Returns

Type

Description

NumberValidator

This validator with both boundary rules appended.

Examples

Validate an age range:

result = v.number(30).between(0, 150).validate()
integer() → NumberValidator

Require a numeric value without a fractional component.

Returns

Type

Description

NumberValidator

This validator.

Examples

Accept an integer-formatted string:

result = v.number("42").integer().validate()
positive() → NumberValidator

Require a numeric value strictly greater than zero.

Returns

Type

Description

NumberValidator

This validator.

Examples

Validate a positive quantity:

result = v.number(1).positive().validate()
non_negative() → NumberValidator

Require a numeric value greater than or equal to zero.

Returns

Type

Description

NumberValidator

This validator.

Examples

Permit zero but reject negative numbers:

result = v.number(0).non_negative().validate()
is_numeric() → NumberValidator

Require successful conversion to float.

Returns

Type

Description

NumberValidator

This validator.

Examples

Validate a numeric string:

result = v.number("3.14").is_numeric().validate()
class ddp_utils.validation.BoolValidator(value: Any = None)

Bases: Validator

Build rules for booleans and recognized boolean strings.

Parameters

Name

Type

Description

value

Any

Optional value stored for later validation.

Examples

Validate a case-insensitive truthy string:

result = BoolValidator("YES").is_bool().validate()

Initialize a validator without rules.

Parameters

Name

Type

Description

value

Any

Optional value stored for validation. A non-None value passed to validate() takes precedence.

Examples

Store a value and add a custom rule later:

validator = Validator("value")
is_bool() → BoolValidator

Require a boolean or a recognized boolean string.

Accepted strings are true, 1, yes, on, y and their false counterparts, compared case-insensitively.

Returns

Type

Description

BoolValidator

This validator.

Examples

Validate an environment-style boolean:

result = v.boolean("off").is_bool().validate()
class ddp_utils.validation.ListValidator(value: Any = None)

Bases: Validator

Build rules for sized and iterable values.

Parameters

Name

Type

Description

value

Any

Optional value stored for later validation.

Examples

Validate a non-empty list of strings:

result = ListValidator(["a", "b"]).not_empty().validate()

Initialize a validator without rules.

Parameters

Name

Type

Description

value

Any

Optional value stored for validation. A non-None value passed to validate() takes precedence.

Examples

Store a value and add a custom rule later:

validator = Validator("value")
min_items(n: int) → ListValidator

Require at least n items in a sized value.

Parameters

Name

Type

Description

n

int

Inclusive minimum item count.

Returns

Type

Description

ListValidator

This validator.

Examples

Require at least two items:

result = v.list([1, 2]).min_items(2).validate()
max_items(n: int) → ListValidator

Allow at most n items in a sized value.

Parameters

Name

Type

Description

n

int

Inclusive maximum item count.

Returns

Type

Description

ListValidator

This validator.

Examples

Limit a list to three items:

result = v.list([1, 2]).max_items(3).validate()
not_empty() → ListValidator

Reject falsey values, including an empty list.

Returns

Type

Description

ListValidator

This validator.

Examples

Reject an empty list:

result = v.list([]).not_empty().validate()
assert not result.ok
each(item_validator: Validator) → ListValidator

Apply another validator to every iterable item.

Parameters

Name

Type

Description

item_validator

Validator

Validator reused for each item. Item errors are prefixed with their zero-based index.

Returns

Type

Description

ListValidator

This validator.

Examples

Require every item to be a positive integer:

result = v.list([1, 2]).each(v.number().positive().integer()).validate()
ddp_utils.validation.validate_dict(data: Dict[str, Any], **field_validators: Validator) → BatchValidationResult

Validate dictionary fields with named validators.

Parameters

Name

Type

Description

data

Dict[str, Any]

Source dictionary. Missing fields are validated as None.

**field_validators

Validator

Mapping expressed as field_name=validator.

Returns

Type

Description

BatchValidationResult

A batch result containing errors only for fields that failed.

Examples

Validate three fields and display any errors:

result = validate_dict(
    {"name": "Alice", "age": 30, "email": "alice@example.com"},
    name=v.string().min(2).max(50),
    age=v.number().between(0, 150).integer(),
    email=v.string().email(),
)
if not result.ok:
    print(result.flat_errors())