An implementation of JSON Schema validation for Python
—
Extensible format checking system supporting built-in formats and custom format validators. Format validation is optional in JSON Schema but provides additional validation capabilities for string values.
The main class for format validation, supporting both built-in and custom format validators.
class FormatChecker:
"""
A format property checker for JSON Schema format keyword validation.
Attributes:
- checkers: Dictionary mapping format names to checker functions
"""
def __init__(self, formats=None):
"""
Initialize format checker.
Parameters:
- formats: Iterable of format names to include (default: all available)
"""
def check(self, instance, format):
"""
Check if instance conforms to the given format.
Parameters:
- instance: Value to check
- format: Format name to validate against
Returns:
- bool: True if valid, False if invalid or format unknown
"""
def checks(self, format, raises=()):
"""
Decorator to register a format checking function.
Parameters:
- format: Format name to register
- raises: Exception types that indicate format errors
Returns:
- decorator: Function decorator
"""
@classmethod
def cls_checks(cls, format, raises=()):
"""
Class method decorator for registering format checkers.
Deprecated: Use instance-based checks() method instead.
Parameters:
- format: Format name to register
- raises: Exception types that indicate format errors
Returns:
- decorator: Function decorator
"""Pre-configured format checkers for each JSON Schema draft version.
# Format checkers for each draft
draft202012_format_checker: FormatChecker
draft201909_format_checker: FormatChecker
draft7_format_checker: FormatChecker
draft6_format_checker: FormatChecker
draft4_format_checker: FormatChecker
draft3_format_checker: FormatCheckerIndividual format checking functions available for custom use.
def is_email(instance):
"""
Check if instance is a valid email address.
Parameters:
- instance: Value to check
Returns:
- bool: True if valid email format
"""
def is_ipv4(instance):
"""
Check if instance is a valid IPv4 address.
Parameters:
- instance: Value to check
Returns:
- bool: True if valid IPv4 address
"""
def is_ipv6(instance):
"""
Check if instance is a valid IPv6 address.
Parameters:
- instance: Value to check
Returns:
- bool: True if valid IPv6 address
"""
def is_regex(instance):
"""
Check if instance is a valid regular expression.
Parameters:
- instance: Value to check
Returns:
- bool: True if valid regex pattern
"""
def is_date(instance):
"""
Check if instance is a valid date string (YYYY-MM-DD).
Parameters:
- instance: Value to check
Returns:
- bool: True if valid date format
"""
def is_uuid(instance):
"""
Check if instance is a valid UUID.
Parameters:
- instance: Value to check
Returns:
- bool: True if valid UUID format
"""
def is_draft3_time(instance):
"""
Check if instance is a valid time string (Draft 3 format).
Parameters:
- instance: Value to check
Returns:
- bool: True if valid time format
"""Format validation functions available when optional dependencies are installed:
# Network and URI validation (requires rfc3986-validator or rfc3987)
def is_uri(instance):
"""Check if instance is a valid URI (requires rfc3986-validator or rfc3987)."""
def is_uri_reference(instance):
"""Check if instance is a valid URI reference (requires rfc3986-validator or rfc3987)."""
def is_iri(instance):
"""Check if instance is a valid IRI (requires rfc3987 or rfc3987-syntax)."""
def is_iri_reference(instance):
"""Check if instance is a valid IRI reference (requires rfc3987 or rfc3987-syntax)."""
# Hostname validation (requires fqdn and idna)
def is_host_name(instance):
"""Check if instance is a valid hostname (requires fqdn)."""
def is_idn_host_name(instance):
"""Check if instance is a valid internationalized hostname (requires idna)."""
# Date/time validation (requires rfc3339-validator)
def is_datetime(instance):
"""Check if instance is a valid RFC 3339 date-time (requires rfc3339-validator)."""
def is_time(instance):
"""Check if instance is a valid time string (requires rfc3339-validator)."""
# JSON Pointer validation (requires jsonpointer)
def is_json_pointer(instance):
"""Check if instance is a valid JSON Pointer (requires jsonpointer)."""
def is_relative_json_pointer(instance):
"""Check if instance is a valid relative JSON Pointer (requires jsonpointer)."""
# Other format validation (requires various packages)
def is_css21_color(instance):
"""Check if instance is a valid CSS 2.1 color (requires webcolors)."""
def is_uri_template(instance):
"""Check if instance is a valid URI template (requires uri-template)."""
def is_duration(instance):
"""Check if instance is a valid ISO 8601 duration (requires isoduration)."""from jsonschema import Draft202012Validator, FormatChecker, ValidationError
schema = {
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"website": {"type": "string", "format": "uri"},
"created": {"type": "string", "format": "date-time"}
}
}
# Create validator with format checking
format_checker = FormatChecker()
validator = Draft202012Validator(schema, format_checker=format_checker)
# Valid data
valid_data = {
"email": "user@example.com",
"website": "https://example.com",
"created": "2023-12-25T10:30:00Z"
}
try:
validator.validate(valid_data)
print("Valid!")
except ValidationError as e:
print(f"Format error: {e.message}")
# Invalid format
invalid_data = {
"email": "not-an-email",
"website": "not-a-uri",
"created": "not-a-datetime"
}
errors = list(validator.iter_errors(invalid_data))
for error in errors:
print(f"Format error: {error.message}")from jsonschema import FormatChecker, Draft202012Validator
# Create custom format checker
format_checker = FormatChecker()
@format_checker.checks('phone')
def is_phone_number(instance):
"""Check if instance is a valid phone number."""
if not isinstance(instance, str):
return False
# Simple phone validation (customize as needed)
import re
pattern = r'^\+?1?-?\.?\s?\(?([0-9]{3})\)?[-\.\s]?([0-9]{3})[-\.\s]?([0-9]{4})$'
return bool(re.match(pattern, instance))
@format_checker.checks('ssn', raises=ValueError)
def is_ssn(instance):
"""Check if instance is a valid SSN."""
if not isinstance(instance, str):
return False
import re
pattern = r'^\d{3}-\d{2}-\d{4}$'
if not re.match(pattern, instance):
raise ValueError("Invalid SSN format")
return True
# Use custom formats in schema
schema = {
"type": "object",
"properties": {
"phone": {"type": "string", "format": "phone"},
"ssn": {"type": "string", "format": "ssn"}
}
}
validator = Draft202012Validator(schema, format_checker=format_checker)
# Test custom formats
test_data = {
"phone": "+1-555-123-4567",
"ssn": "123-45-6789"
}
validator.validate(test_data) # Should passfrom jsonschema import FormatChecker, Draft202012Validator
# Create format checker with only specific formats
format_checker = FormatChecker(['email', 'date', 'ipv4'])
schema = {
"type": "object",
"properties": {
"email": {"type": "string", "format": "email"},
"date": {"type": "string", "format": "date"},
"ip": {"type": "string", "format": "ipv4"},
"uri": {"type": "string", "format": "uri"} # This won't be checked
}
}
validator = Draft202012Validator(schema, format_checker=format_checker)
data = {
"email": "user@example.com",
"date": "2023-12-25",
"ip": "192.168.1.1",
"uri": "not-a-valid-uri" # No error - format not enabled
}
validator.validate(data) # Passes because 'uri' format not checkedfrom jsonschema._format import is_email, is_ipv4, is_date
# Direct format checking
print(is_email("user@example.com")) # True
print(is_email("invalid-email")) # False
print(is_ipv4("192.168.1.1")) # True
print(is_ipv4("999.999.999.999")) # False
print(is_date("2023-12-25")) # True
print(is_date("invalid-date")) # Falsefrom jsonschema import Draft202012Validator, FormatChecker, ValidationError
format_checker = FormatChecker()
schema = {"type": "string", "format": "email"}
validator = Draft202012Validator(schema, format_checker=format_checker)
try:
validator.validate("not-an-email")
except ValidationError as e:
print(f"Format validation failed: {e.message}")
print(f"Validator: {e.validator}") # 'format'
print(f"Format: {e.validator_value}") # 'email'
print(f"Instance: {e.instance}") # 'not-an-email'Common formats supported by the built-in format checkers:
Format availability may vary by draft version and optional dependencies.
Install with Tessl CLI
npx tessl i tessl/pypi-jsonschema