Show HN: Validatedata 0.3.0 – lightweight inline data validation for Python
by EdwardK1 | 2026-03-03 21:48:16+00:00
Validatedata is a Python library for validating dicts, lists, function arguments, and API payloads inline. No model classes, no boilerplate — just rules alongside the data.
pip install validatedata

Three ways to use it
1. Standalone function — validate a dict
pythonfrom validatedata import validate_data

result = validate_data(
data={'username': 'alice', 'email': 'alice@example.com', 'age': 25},
rule={'keys': {
'username': 'str|min:3|max:32',
'email': 'email',
'age': 'int|min:18',
}}
)

result.ok # True
result.errors # []

# on failure:
# [['username: invalid string length'], ['age: number out of range']]
2. Decorator — validate function arguments
pythonfrom validatedata import validate

@validate(['str|min:3|max:32', 'email', 'str|min:8|msg:password too weak'])
def signup(username, email, password):
return 'Account Created'

signup('alice', 'alice@example.com', 'Secure@123') # works
signup('alice', 'not-an-email', 'weak') # returns {'errors': [...]}
3. Type annotation decorator
pythonfrom validatedata import validate_types

@validate_types
def create_user(username: str, age: int):
return f'{username} ({age})'

create_user('alice', 30) # works
create_user('alice', 'thirty') # raises ValidationError
All three support async functions transparently.

Shorthand rule syntax
Rules can be written as compact pipe-separated strings. Transforms, validators, and custom messages chain in one line:
python'str|min:3|max:32'
'email|nullable'
'int|between:0,100'
'str|strip|lower|in:admin,editor,viewer|msg:invalid role'
'str|min:8|re:(?=.[A-Z])(?=.\d).+|msg:password must contain uppercase and a number'
'color|format:hex|nullable'
'url|starts_with:https|msg:must be a secure URL'
Named transforms (strip, lstrip, rstrip, lower, upper, title) run before validation. msg: is always last.

Transforms and mutation
Apply transforms before validation and get cleaned values back:
pythonresult = validate_data(
data=[' Alice ', ' bob '],
rule=['str|strip|lower', 'str|strip|lower'],
mutate=True
)

result.ok # True
result.data # ['alice', 'bob']

Conditional validation
Validate a field only when a sibling field meets a condition:
pythonrule = {'keys': {
'role': {'type': 'str'},
'permissions': {
'type': 'str',
'depends_on': {'field': 'role', 'value': 'admin'},
'options': ('full', 'read', 'none')
}
}}

# permissions only validated when role == 'admin'

Custom error messages
Any rule key accepts a {rule}-message override:
python{
'type': 'int',
'range': (18, 'any'),
'range-message': 'you must be at least 18',
'type-message': 'age must be a number',
}
Shorthand: 'int|min:18|msg:you must be at least 18'

Supported types
Basic: str, int, float, bool, email, url, ip, uuid, slug, semver, phone, color, date, even, odd, prime
Extended: dict, list, tuple, set, regex, object
Phone validation supports E.164 built-in. National, international, and region-specific formats available via pip install phonenumbers.
Color validation supports hex, rgb, hsl, and named CSS colors.

Supported rules
range, length, contains, excludes, options, expression, startswith, endswith, unique, nullable, strict, transform, depends_on, fields, items

Return value
validate_data returns a SimpleNamespace:

result.ok — True if all validation passed
result.errors — list of error groups, one per field
result.data — transformed values, only present when mutate=True

MIT licensed. Python 3.7+. No required dependencies.
Repo: https://github.com/Edward-K1/validatedata
PyPI: https://pypi.org/project/validatedata/
Feedback, bug reports, and use-case stories welcome.