Source code for campos.validators

import re
import abc
import math
from datetime import date, time, datetime

__author__ = 'Juan Manuel Bermúdez Cabrera'


[docs]class Validator(metaclass=abc.ABCMeta): """Base class for field validation. Subclasses must define a ``__call__(self, field)`` method which validates the current value of `field` and raises a ValueError error if it is not valid. :param message: message to show when an invalid value is found. :type message: :class:`str` """ def __init__(self, message='Invalid data'): self.message = message @abc.abstractmethod def __call__(self, field): pass
[docs]class DataRequired(Validator): """Checks if a field is not empty. Only basic validations are done here, the following values are considered invalid: * None * Empty strings or containing only blank spaces. * Numbers when :func:`math.isfinite` is `False`. * Empty collections. * Time objects if its evaluation in a boolean context is False :param message: message to show when no data is found :type message: :class:`str` """ def __init__(self, message='Required'): super(DataRequired, self).__init__(message=message) def __call__(self, field): value = field.value valid = True if value is None: valid = False elif isinstance(value, str): valid = len(value.strip()) > 0 elif isinstance(value, (int, float)): valid = math.isfinite(value) elif hasattr(value, '__len__'): valid = len(value) > 0 elif isinstance(value, time) and not value: valid = False if not valid: raise ValueError(self.message)
[docs]class NumberRange(Validator): """Number range validation. :param min: minimum valid value, defaults to 0 :type min: :class:`int` or :class:`float` :param max: maximum valid value, defaults to 100 :type max: :class:`int` or :class:`float` :param message: message to show if ``not min <= value <= max`` :type message: :class:`str` """ def __init__(self, min=0, max=100, message=None): super(NumberRange, self).__init__(message=message) self.min = min self.max = max def __call__(self, field): value = field.value if not self.min <= value <= self.max: message = self.message if self.message is None: message = 'Value must be between {} and {}' message = message.format(self.min, self.max) raise ValueError(message)
[docs]class StringLength(Validator): """String length validation. :param min: minimum valid length, defaults to 0 :type min: :class:`int` :param max: maximum valid length, defaults to 100 :type max: :class:`int` :param message: message to show if ``not min <= len(value) <= max`` :type message: :class:`str` """ def __init__(self, min=0, max=100, message=None): super(StringLength, self).__init__(message=message) self.min = min self.max = max def __call__(self, field): value = field.value if not self.min <= len(value) <= self.max: message = self.message if self.message is None: message = 'Value must be between {} and {} characters long' message = message.format(self.min, self.max) raise ValueError(message)
[docs]class RegExp(Validator): """Validate text against a regular expression. :param exp: string or compiled regular expression :type exp: :class:`str` or compiled re :param flags: flags to pass to :func:`re.compile` if it's necessary :type flags: :class:`int` :param message: message to show if value doesn't fully match the regular expression :type message: :class:`str` """ def __init__(self, exp, flags=0, message="Value doesn't match pattern"): super(RegExp, self).__init__(message=message) self.compiled = re.compile(exp, flags) if isinstance(exp, str) else exp def __call__(self, field): if not self.compiled.fullmatch(field.value): raise ValueError(self.message)
[docs]class DateRange(Validator): """Range validation for :class:`datetime.date` objects. :param min: minimum valid date, defaults to the current date :type min: :class:`datetime.date` :param max: maximum valid date, defaults to `date.max` :type max: :class:`datetime.date` :param message: message to show if ``not min <= value <= max`` :type message: :class:`str` """ def __init__(self, min=date.today(), max=date.max, message=None): super(DateRange, self).__init__(message=message) self.min = min self.max = max def __call__(self, field): value = field.value if not self.min <= value <= self.max: message = self.message if self.message is None: message = 'Date must be between {} and {}' message = message.format(self.min, self.max) raise ValueError(message)
[docs]class TimeRange(Validator): """Range validation for :class:`datetime.time` objects. :param min: minimum valid time, defaults to :attr:`datetime.time.min` :type min: :class:`datetime.time` :param max: maximum valid time, defaults to :attr:`datetime.time.max` :type min: :class:`datetime.time` :param message: message to show if ``not min <= value <= max`` :type message: :class:`str` """ def __init__(self, min=time.min, max=time.max, message=None): super(TimeRange, self).__init__(message=message) self.min = min self.max = max def __call__(self, field): value = field.value if not self.min <= value <= self.max: message = self.message if self.message is None: message = 'Time must be between {} and {}' message = message.format(self.min, self.max) raise ValueError(message)
[docs]class DatetimeRange(Validator): """Range validation for :class:`datetime.datetime` objects. :param min: minimum valid datetime, defaults to :attr:`datetime.datetime.min` :type min: :class:`datetime.datetime` :param max: maximum valid datetime, defaults to :attr:`datetime.datetime.max` :type min: :class:`datetime.datetime` :param message: message to show if ``not min <= value <= max`` :type message: :class:`str` """ def __init__(self, min=datetime.min, max=datetime.max, message=None): super(DatetimeRange, self).__init__(message=message) self.min = min self.max = max def __call__(self, field): value = field.value if not self.min <= value <= self.max: message = self.message if self.message is None: message = 'Date and time must be between {} and {}' message = message.format(self.min, self.max) raise ValueError(message)