Source code for tortoise.validators
from __future__ import annotations
import abc
import ipaddress
import re
from decimal import Decimal
from typing import Any
from tortoise.exceptions import ValidationError
[docs]class Validator(metaclass=abc.ABCMeta):
[docs] @abc.abstractmethod
def __call__(self, value: Any) -> None:
"""
All specific validators should implement this method.
:param value: The given value to be validated.
:raises ValidationError: if validation failed.
"""
[docs]class RegexValidator(Validator):
"""
A validator to validate the given value whether match regex or not.
"""
def __init__(self, pattern: str, flags: int | re.RegexFlag) -> None:
self.regex = re.compile(pattern, flags)
def __call__(self, value: Any) -> None:
if not self.regex.match(value):
raise ValidationError(f"Value '{value}' does not match regex '{self.regex.pattern}'")
[docs]class MaxLengthValidator(Validator):
"""
A validator to validate the length of given value whether greater than max_length or not.
"""
def __init__(self, max_length: int) -> None:
self.max_length = max_length
def __call__(self, value: str) -> None:
if value is None:
raise ValidationError("Value must not be None")
if len(value) > self.max_length:
raise ValidationError(f"Length of '{value}' {len(value)} > {self.max_length}")
[docs]class MinLengthValidator(Validator):
"""
A validator to validate the length of given value whether less than min_length or not.
"""
def __init__(self, min_length: int) -> None:
self.min_length = min_length
def __call__(self, value: str) -> None:
if value is None:
raise ValidationError("Value must not be None")
if len(value) < self.min_length:
raise ValidationError(f"Length of '{value}' {len(value)} < {self.min_length}")
[docs]class NumericValidator(Validator):
types = (int, float, Decimal)
def _validate_type(self, value: Any) -> None:
if not isinstance(value, self.types):
raise ValidationError("Value must be a numeric value and is required")
[docs]class MinValueValidator(NumericValidator):
"""
Min value validator for FloatField, IntField, SmallIntField, BigIntField
"""
def __init__(self, min_value: int | float | Decimal) -> None:
self._validate_type(min_value)
self.min_value = min_value
def __call__(self, value: int | float | Decimal) -> None:
self._validate_type(value)
if value < self.min_value:
raise ValidationError(f"Value should be greater or equal to {self.min_value}")
[docs]class MaxValueValidator(NumericValidator):
"""
Max value validator for FloatField, IntField, SmallIntField, BigIntField
"""
def __init__(self, max_value: int | float | Decimal) -> None:
self._validate_type(max_value)
self.max_value = max_value
def __call__(self, value: int | float | Decimal) -> None:
self._validate_type(value)
if value > self.max_value:
raise ValidationError(f"Value should be less or equal to {self.max_value}")
[docs]class CommaSeparatedIntegerListValidator(Validator):
"""
A validator to validate whether the given value is valid comma separated integer list or not.
"""
def __init__(self, allow_negative: bool = False) -> None:
pattern = r"^%(neg)s\d+(?:%(sep)s%(neg)s\d+)*\Z" % {
"neg": "(-)?" if allow_negative else "",
"sep": re.escape(","),
}
self.regex = RegexValidator(pattern, re.I)
def __call__(self, value: str) -> None:
self.regex(value)
[docs]def validate_ipv4_address(value: Any) -> None:
"""
A validator to validate whether the given value is valid IPv4Address or not.
:raises ValidationError: if value is invalid IPv4Address.
"""
try:
ipaddress.IPv4Address(value)
except ValueError:
raise ValidationError(f"'{value}' is not a valid IPv4 address.")
[docs]def validate_ipv6_address(value: Any) -> None:
"""
A validator to validate whether the given value is valid IPv6Address or not.
:raises ValidationError: if value is invalid IPv6Address.
"""
try:
ipaddress.IPv6Address(value)
except ValueError:
raise ValidationError(f"'{value}' is not a valid IPv6 address.")
[docs]def validate_ipv46_address(value: Any) -> None:
"""
A validator to validate whether the given value is valid IPv4Address or IPv6Address or not.
:raises ValidationError: if value is invalid IPv4Address or IPv6Address.
"""
try:
validate_ipv4_address(value)
except ValidationError:
try:
validate_ipv6_address(value)
except ValidationError:
raise ValidationError(f"'{value}' is not a valid IPv4 or IPv6 address.")