validators
Validation Library
validators
Overview
validators is a simple and user-friendly Python validation library with the concept of "Python Data Validation for Humans™". Its main feature is the ability to easily validate single values without defining complex schemas or forms.
It provides various validation functions frequently needed in web application development, such as URLs, email addresses, IP addresses, UUIDs, and domain names. Each validator is implemented as an independent function with a consistent interface that returns True on successful validation and a ValidationFailure object on failure.
Details
validators is a library designed to perform Python data validation in a concise and intuitive manner. While many validation libraries require schema definitions, validators focuses on simple value validation and is designed to be implemented with minimal code.
Key Features
1. Simple API Design
import validators
# Email validation
validators.email('[email protected]') # Returns True
2. Rich Validation Features
- URL Validation: Adopts dperini's highly accurate URL validation algorithm
- Email Address Validation: Based on Django's Email validator
- IP Address Validation: Supports both IPv4 and IPv6 (WTForms compliant)
- Domain Name Validation: Supports Internationalized Domain Names (IDN)
- UUID Validation: Validates RFC 4122 compliant UUID format
- IBAN Validation: International Bank Account Number validation
- MAC Validation: MAC address format validation
- BTC Address Validation: Bitcoin address validation (full P2PKH and P2SH support)
- Slug Validation: URL-friendly string validation
- Length Validation: String length range validation
- Range Validation: Range validation for numbers, dates, etc.
3. Consistent Return Value Design
All validator functions return True on successful validation and a ValidationFailure object on failure. Since ValidationFailure implements the __bool__ method, error checking is easy with regular if statements.
4. Latest Version Improvements (v0.35.0)
- Support for
.oniondomain validation - Allow hashtag characters in URL fragments
- Fixed email regex
- Support for special DOI cases
- Improved URI validation
Pros and Cons
Pros
-
Low Learning Curve
- No schema definition required, can start using immediately
- Each function is independent, allowing selective use of only needed features
-
Fast and Lightweight
- Few dependencies, minimal impact on performance
- Simple implementation achieves fast validation processing
-
Proven Implementation
- Based on validators from proven frameworks like Django and WTForms
- Adopts industry-standard algorithms like dperini's URL validation
-
Flexible Integration
- Easy to introduce into existing projects
- Can be used alongside other validation libraries
-
Internationalization Support
- Supports Internationalized Domain Names (IDN)
- Compatible with various national standards (IBAN, etc.)
Cons
-
Lack of Advanced Validation Features
- Difficult to define complex conditional validation or custom rules
- Not suitable for validating nested data structures
-
Limited Error Message Customization
- Limited options for detailed error message customization
- Multilingual error messages need to be implemented manually
-
No Type Annotation Support
- Does not support type-based validation like Pydantic
- Weak integration with static type checking
-
Lack of Schema-Based Validation
- Separate implementation needed for cross-field validation
- No integration of data model definition and validation
Reference Pages
Code Examples
Basic Usage
import validators
# Installation
# pip install validators
# Basic validation pattern
if validators.email('[email protected]'):
print("Valid email address")
else:
print("Invalid email address")
# Handling ValidationFailure objects
result = validators.url('not-a-url')
if not result:
print(f"Validation failed: {result}")
URL Validation
import validators
# Basic URL validation
print(validators.url('https://example.com')) # True
print(validators.url('http://localhost:8080')) # True
print(validators.url('ftp://files.example.com')) # True
# Invalid URL example
result = validators.url('not a url')
if not result:
print("URL is invalid")
# Allow only HTTPS (custom logic)
def validate_https_url(url):
if validators.url(url) and url.startswith('https://'):
return True
return False
print(validate_https_url('https://secure.example.com')) # True
print(validate_https_url('http://insecure.example.com')) # False
Email Address Validation
import validators
# Basic email validation
emails = [
'[email protected]',
'[email protected]',
'invalid.email@',
'@example.com',
'[email protected]'
]
for email in emails:
result = validators.email(email)
status = "Valid" if result else "Invalid"
print(f"{email}: {status}")
# Form validation example
def validate_registration_form(form_data):
errors = {}
if not validators.email(form_data.get('email', '')):
errors['email'] = 'Invalid email address'
if not validators.length(form_data.get('password', ''), min=8):
errors['password'] = 'Password must be at least 8 characters'
return errors
IP Address Validation
import validators
# IPv4 address validation
ipv4_addresses = [
'192.168.1.1',
'10.0.0.1',
'256.256.256.256', # Invalid
'192.168.1' # Invalid
]
for ip in ipv4_addresses:
if validators.ipv4(ip):
print(f"{ip} is a valid IPv4 address")
else:
print(f"{ip} is an invalid IPv4 address")
# IPv6 address validation
ipv6_addresses = [
'2001:0db8:85a3:0000:0000:8a2e:0370:7334',
'2001:db8:85a3::8a2e:370:7334', # Shortened form
'fe80::1',
'invalid::address::format' # Invalid
]
for ip in ipv6_addresses:
if validators.ipv6(ip):
print(f"{ip} is a valid IPv6 address")
# Determine IP address type
def get_ip_type(ip_address):
if validators.ipv4(ip_address):
return "IPv4"
elif validators.ipv6(ip_address):
return "IPv6"
else:
return "Invalid IP address"
Domain Name and UUID Validation
import validators
import uuid
# Domain name validation
domains = [
'example.com',
'sub.example.com',
'example.co.jp',
'にほん.jp', # Internationalized domain name
'example.onion', # Tor domain
'invalid domain.com', # Invalid (contains space)
'.com' # Invalid
]
for domain in domains:
if validators.domain(domain):
print(f"{domain} is a valid domain name")
# UUID validation
test_uuids = [
str(uuid.uuid4()), # Valid UUID
'550e8400-e29b-41d4-a716-446655440000', # Valid
'not-a-uuid', # Invalid
'550e8400-e29b-41d4-a716' # Invalid (too short)
]
for test_uuid in test_uuids:
if validators.uuid(test_uuid):
print(f"{test_uuid} is a valid UUID")
# Slug validation (URL-friendly strings)
slugs = [
'my-blog-post',
'article_2024',
'post-123',
'invalid slug!', # Invalid (special character)
'my.post' # Invalid (contains dot)
]
for slug in slugs:
if validators.slug(slug):
print(f"'{slug}' is a valid slug")
Advanced Validation Patterns
import validators
from datetime import datetime, date
# String length validation
passwords = [
'short',
'minimum8chars',
'this_is_a_very_long_password_that_exceeds_maximum'
]
for password in passwords:
if validators.length(password, min=8, max=32):
print(f"Password '{password}' is valid")
else:
print(f"Password '{password}' must be 8-32 characters")
# Numeric range validation
ages = [15, 18, 25, 65, 120]
for age in ages:
if validators.between(age, min=18, max=100):
print(f"Age {age} is valid")
else:
print(f"Age {age} is outside the 18-100 range")
# Date range validation
dates = [
date(2020, 1, 1),
date(2024, 6, 15),
date(2025, 12, 31)
]
min_date = date(2023, 1, 1)
max_date = date(2025, 1, 1)
for d in dates:
if validators.between(d, min=min_date, max=max_date):
print(f"{d} is within the valid date range")
# Example combining multiple validations
def validate_user_input(data):
"""Comprehensive validation of user input"""
errors = []
# Email validation
if not validators.email(data.get('email', '')):
errors.append('Invalid email address')
# URL validation (optional)
if data.get('website') and not validators.url(data['website']):
errors.append('Invalid website URL')
# Age validation
age = data.get('age', 0)
if not validators.between(age, min=13, max=120):
errors.append('Age must be between 13 and 120')
# Username (slug) validation
if not validators.slug(data.get('username', '')):
errors.append('Username can only contain alphanumeric characters, hyphens, and underscores')
return errors
# Usage example
user_data = {
'email': '[email protected]',
'website': 'https://mysite.com',
'age': 25,
'username': 'john_doe'
}
errors = validate_user_input(user_data)
if errors:
print("Validation errors:")
for error in errors:
print(f" - {error}")
else:
print("All inputs are valid")
# Combining with custom validators
def validate_us_phone(phone):
"""Custom function to validate US phone numbers"""
import re
# Simple US phone number pattern
pattern = r'^\+?1?\d{10}$|^\d{3}-\d{3}-\d{4}$'
return bool(re.match(pattern, phone))
# Using with validators
def validate_contact_info(info):
errors = {}
if not validators.email(info.get('email', '')):
errors['email'] = 'Please enter a valid email address'
if not validate_us_phone(info.get('phone', '')):
errors['phone'] = 'Please enter a valid US phone number'
return errors
# Real-world application example
class UserRegistrationValidator:
"""User registration form validator"""
@staticmethod
def validate(data):
errors = {}
# Required field validation
if not data.get('username'):
errors['username'] = 'Username is required'
elif not validators.slug(data['username']):
errors['username'] = 'Username must be URL-friendly'
elif not validators.length(data['username'], min=3, max=20):
errors['username'] = 'Username must be 3-20 characters'
# Email validation
if not data.get('email'):
errors['email'] = 'Email is required'
elif not validators.email(data['email']):
errors['email'] = 'Invalid email address'
# Password validation
if not data.get('password'):
errors['password'] = 'Password is required'
elif not validators.length(data['password'], min=8):
errors['password'] = 'Password must be at least 8 characters'
# Optional website validation
if data.get('website') and not validators.url(data['website']):
errors['website'] = 'Invalid website URL'
return errors
@staticmethod
def is_valid(data):
"""Check if data is valid"""
return len(UserRegistrationValidator.validate(data)) == 0
# Example usage
registration_data = {
'username': 'john_doe',
'email': '[email protected]',
'password': 'securepassword123',
'website': 'https://johndoe.com'
}
if UserRegistrationValidator.is_valid(registration_data):
print("Registration data is valid!")
else:
errors = UserRegistrationValidator.validate(registration_data)
print("Validation errors:", errors)