# Source code for staticconf.validation

    """
    Validate a configuration value by converting it to a specific type.

    These functions are used by :mod:`staticconf.readers` and
    :mod:`staticconf.schema` to coerce config values to a type.
    """
    import datetime
    import logging
    import re
    import time

    import six

    from staticconf.errors import ValidationError

    def validate_string(value):
        return None if value is None else six.text_type(value)

    def validate_bool(value):
        return None if value is None else bool(value)

    def validate_numeric(type_func, value):
        try:
            return type_func(value)
        except ValueError:
            raise ValidationError("Invalid %s: %s" % (type_func.__name__, value))

    def validate_int(value):
        return validate_numeric(int, value)

    def validate_float(value):
        return validate_numeric(float, value)

    date_formats = [
        "%Y-%m-%d %H:%M:%S",
        "%Y-%m-%d %I:%M:%S %p",
        "%Y-%m-%d",
        "%y-%m-%d",
        "%m/%d/%y",
        "%m/%d/%Y",
    ]

    def validate_datetime(value):
        if isinstance(value, datetime.datetime):
            return value

        for format_ in date_formats:
            try:
                return datetime.datetime.strptime(value, format_)
            except ValueError:
                pass
        raise ValidationError("Invalid date format: %s" % value)

    def validate_date(value):
        if isinstance(value, datetime.date):
            return value

        return validate_datetime(value).date()

    time_formats = [
        "%I %p",
        "%H:%M",
        "%I:%M %p",
        "%H:%M:%S",
        "%I:%M:%S %p"
    ]

    def validate_time(value):
        if isinstance(value, datetime.time):
            return value

        for format_ in time_formats:
            try:
                return datetime.time(*time.strptime(value, format_)[3:6])
            except ValueError:
                pass
        raise ValidationError("Invalid time format: %s" % value)

    def _validate_iterable(iterable_type, value):
        """Convert the iterable to iterable_type, or raise a Configuration
        exception.
        """
        if isinstance(value, six.string_types):
            msg = "Invalid iterable of type(%s): %s"
            raise ValidationError(msg % (type(value), value))

        try:
            return iterable_type(value)
        except TypeError:
            raise ValidationError("Invalid iterable: %s" % (value))

    def validate_list(value):
        return _validate_iterable(list, value)

    def validate_set(value):
        return _validate_iterable(set, value)

    def validate_tuple(value):
        return _validate_iterable(tuple, value)

    def validate_regex(value):
        try:
            return re.compile(value)
        except (re.error, TypeError) as e:
            raise ValidationError("Invalid regex: %s, %s" % (e, value))

    def build_list_type_validator(item_validator):
        """Return a function which validates that the value is a list of items
        which are validated using item_validator.
        """
        def validate_list_of_type(value):
            return [item_validator(item) for item in validate_list(value)]
        return validate_list_of_type

    def build_map_type_validator(item_validator):
        """Return a function which validates that the value is a mapping of
        items. The function should return pairs of items that will be
        passed to the `dict` constructor.
        """
        def validate_mapping(value):
            return dict(item_validator(item) for item in validate_list(value))
        return validate_mapping

    def validate_log_level(value):
        """Validate a log level from a string value. Returns a constant from
        the :mod:`logging` module.
        """
        try:
            return getattr(logging, value)
        except AttributeError:
            raise ValidationError("Unknown log level: %s" % value)

    def validate_any(value):
        return value

    validators = {
        '':          validate_any,
        'bool':      validate_bool,
        'date':      validate_date,
        'datetime':  validate_datetime,
        'float':     validate_float,
        'int':       validate_int,
        'list':      validate_list,
        'set':       validate_set,
        'string':    validate_string,
        'time':      validate_time,
        'tuple':     validate_tuple,
        'regex':     validate_regex,
        'log_level': validate_log_level,
    }

    def get_validators():
        """Return an iterator of (validator_name, validator) pairs."""
        return six.iteritems(validators)