Fluent, composable data validation for Python — a simple, expressive API to build readable validation rules.
fluent_validator makes it easy to declare validation rules in a fluent, composable way. Build reusable specifications with clear messages and combine them using logical operators.
- Installation
- Quick start
- Combining validators
- describe (document rules)
- Available validations
- Validation strategies
- Quick API
Install from PyPI:
pip install fluent-validatorBasic usage examples:
from fluent_validator import Validator, ValidationError
# build a composed specification
spec = (
Validator.is_number()
.is_greater_than(5)
.is_less_than(20)
)
# validate (default: raise_after_first_error)
try:
spec.validate(7)
print("Valid")
except ValidationError as e:
print("Invalid:", e)
# get boolean result without raising
is_valid = spec.validate(7, strategy="return_result") # True/False
# validate each item of an iterable
list_spec = Validator.is_iterable().contains_at_least(2)
list_spec.validate_each([1, 2, 3], strategy="return_result") # TrueSpecifications can be combined with logical operators:
# AND (concatenate validations)
a = Validator.is_number().is_gte(0)
b = Validator.is_number().is_lte(100)
combined = a & b
combined.validate(50)
# OR (at least one group must pass)
num_or_str = Validator.is_number() | Validator.is_string()
num_or_str.validate("abc", strategy="return_result") # True
# Negation
not_none = ~Validator.is_none()
not_none.validate(None, strategy="return_result") # FalseEach ValidatorSpec can render a textual description of the specification. Here's a more complex example combining AND, OR and negation:
spec = (
(Validator.is_number().is_between(10, 20) | Validator.is_none())
& ~Validator.is_string()
)
print(spec.describe())
print(spec.describe(pretty=True))Example output for pretty=True:
(
(
'Should be a number (rule: is_number)' AND
'Should be between 10 and 20 (closed='both') (rule: is_between)'
)
OR
'Should be None (rule: is_none)'
)
AND not 'Should be a string (rule: is_string)'
Use describe() to generate messages for logs, documentation, or custom error reporting.
Below is a table of validator builder functions and a short description of each.
| Function | Description |
|---|---|
is_instance_of(types)is_not_instance_of(types) |
Checks the value is an instance of the provided types. |
is_callable()is_not_callable() |
Checks the value is callable. |
is_iterable()is_not_iterable() |
Checks the value is iterable. |
is_dataclass()is_not_dataclass() |
Checks the value is a dataclass. |
is_string()is_not_string() |
Checks the value is a string. |
is_number()is_not_number() |
Checks the value is numeric (int, float, Decimal). |
is_bool()is_not_bool() |
Checks the value is a boolean. |
is_none()is_not_none() |
Checks the value is None. |
is_greater_than(value) (is_gt)is_not_greater_than(value) |
Checks the value is greater than value. |
is_greater_or_equal(value) (is_gte)is_not_greater_or_equal(value) |
Checks the value is greater than or equal to value. |
is_equal(value) (is_eq)is_not_equal(value) |
Checks the value is equal to value. |
is_less_than(value) (is_lt)is_not_less_than(value) |
Checks the value is less than value. |
is_less_or_equal(value) (is_lte)is_not_less_or_equal(value) |
Checks the value is less than or equal to value. |
is_between(lower, upper, closed='both')is_not_between(...) |
Checks the value is between lower and upper (closed/open according to closed). |
contains_at_least(n)contains_at_most(n)contains_exactly(n) |
Checks collection size (at least/at most/exactly n items). |
has_unique_values() |
Checks that values in a collection are unique. |
is_empty()is_not_empty() |
Checks if the collection/value is empty. |
is_true()is_not_true()is_false()is_not_false() |
Checks boolean True/False values. |
is_in(collection)is_not_in(collection) |
Checks if the value is in collection. |
add_validation(fn, msg)add_validations(list[(fn, msg)]) |
Adds custom validations by providing functions and messages. |
See the function and class docstrings in the source for details and default messages.
The validate method accepts a strategy parameter:
raise_after_first_error(default): raisesValidationErroron the first failing rule.raise_after_all_errors: evaluates all rules and raisesValidationErrorwith all messages joined.return_result: does not raise; returnsTrueif the value passes all rules orFalseotherwise.
Use validate_each to validate every item in an iterable; errors include the failing item index when applicable.
Primary imports:
from fluent_validator import Validator, ValidatorSpec, ValidationErrorValidatorprovides factory classmethods (e.g.is_number(),is_string()) returning configuredValidatorSpecinstances.ValidatorSpecis the builder that lets you chain validations, combine specs with&,|, negate with unary-, and calldescribe()/validate().
MIT License — see LICENSE.
Open an issue: https://github.com/mariotaddeucci/fluent_validator/issues
Happy validating! 🚀