def validate_string(typedef, value):
    """
    Validate a string, check length.
    """

    # Check to see if the typedef has any pattern restrictions. If it does,
    # then match against all of the patterns. If it matches any
    # of the patterns (i.e. not all of the patterns), then the argument
    # value is considered to be valid.
    patterns = typedef.get('pattern')
    if patterns:
        # If it's a single pattern convert it to a tuple, so we can handle
        # it in a common way below. Note that we don't use collection.Sequence
        # in the isinstance call because strings are sequences
        if command._is_string(patterns):
            patterns = (patterns,)

        for pattern in patterns:
            if re.match(pattern, str(value)):
                break
        else:
            command._raise_argument_validation_exception(typedef, value,
                                                        'invalid string pattern')

    # Check for any length restrictions. This can be a single scalar length or
    # a single length range or a sequence of either of those. For scalar lengths
    # the length must match it exactly. For length ranges the length of the argument
    # must be between the two values (inclusive). For a list of length specs, the
    # length must match any of the lengths (either scalar or range) in the list.
    lengths = typedef.get('length')
    if lengths:
        if command._is_single_range(lengths):
            lengths = (lengths,)
        for length in lengths:
            command._check_one_range(length)
            if isinstance(length, numbers.Integral):
                if len(value) == length:
                    break
            if len(value) >= length[0] and len(value) <= length[1]:
                break
        else:
            command._raise_argument_validation_exception(typedef, value,
                                                        'invalid string length')

    return value
def validate_string(typedef, value):
    """
    Validate a string, check length.
    """

    # Check to see if the typedef has any pattern restrictions. If it does,
    # then match against all of the patterns. If it matches any
    # of the patterns (i.e. not all of the patterns), then the argument
    # value is considered to be valid.
    patterns = typedef.get('pattern')
    if patterns:
        # If it's a single pattern convert it to a tuple, so we can handle
        # it in a common way below. Note that we don't use collection.Sequence
        # in the isinstance call because strings are sequences
        if command._is_string(patterns):
            patterns = (patterns,)

        for pattern in patterns:
            if re.match(pattern, str(value)):
                break
        else:
            command._raise_argument_validation_exception(typedef, value,
                                                        'invalid string pattern')

    # Check for any length restrictions. This can be a single scalar length or
    # a single length range or a sequence of either of those. For scalar lengths
    # the length must match it exactly. For length ranges the length of the argument
    # must be between the two values (inclusive). For a list of length specs, the
    # length must match any of the lengths (either scalar or range) in the list.
    lengths = typedef.get('length')
    if lengths:
        if command._is_single_range(lengths):
            lengths = (lengths,)
        for length in lengths:
            command._check_one_range(length)
            if isinstance(length, numbers.Integral):
                if len(value) == length:
                    break
            if len(value) >= length[0] and len(value) <= length[1]:
                break
        else:
            command._raise_argument_validation_exception(typedef, value,
                                                        'invalid string length')

    return value
def validate_enum(typedef, value):
    # FIXME: Sort of a hack. The base enum class doesn't have a values
    # field, so there's nothing to check against. We really just use it
    # as a base type to indicate the validation function (i.e. this function)
    # to use.
    name = typedef.get('name')
    if name == 'enum':
        return

    enum_values = typedef.get('values')
    if not enum_values:
        raise error.CommandDescriptionError('Unspecified enum values')

    if not isinstance(enum_values, collections.Mapping):
        # If it's not a dictionary then it should be an array
        # or tuple where the (string) elements are both the key
        # and the value for the enum items. So here we convert
        # to a dictionary so we can use the same logic for both
        # cases below.
        if command._is_string(enum_values):
            enum_values = (enum_values,)
        if isinstance(enum_values, collections.Sequence):
            enum_values = dict((v,v) for v in enum_values)
        else:
            raise error.CommandDescriptionError(
                    'Enum values must be either a string, dict, tuple, or list')

    prefix_matches = []
    lower_value = value.lower()
    for enum_value, return_value in enum_values.items():
        lower_enum_value = enum_value.lower()
        if lower_enum_value == lower_value:
            return (return_value, enum_value)
        if lower_enum_value.startswith(lower_value):
            prefix_matches.append((return_value, enum_value))

    if len(prefix_matches) == 0:
        command._raise_argument_validation_exception(typedef, value,
                'unexpected value for enum', enum_values.keys())

    return prefix_matches
def validate_enum(typedef, value):
    # FIXME: Sort of a hack. The base enum class doesn't have a values
    # field, so there's nothing to check against. We really just use it
    # as a base type to indicate the validation function (i.e. this function)
    # to use.
    name = typedef.get('name')
    if name == 'enum':
        return

    enum_values = typedef.get('values')
    if not enum_values:
        raise error.CommandDescriptionError('Unspecified enum values')

    if not isinstance(enum_values, collections.Mapping):
        # If it's not a dictionary then it should be an array
        # or tuple where the (string) elements are both the key
        # and the value for the enum items. So here we convert
        # to a dictionary so we can use the same logic for both
        # cases below.
        if command._is_string(enum_values):
            enum_values = (enum_values,)
        if isinstance(enum_values, collections.Sequence):
            enum_values = dict((v,v) for v in enum_values)
        else:
            raise error.CommandDescriptionError(
                    'Enum values must be either a string, dict, tuple, or list')

    prefix_matches = []
    lower_value = value.lower()
    for enum_value, return_value in enum_values.items():
        lower_enum_value = enum_value.lower()
        if lower_enum_value == lower_value:
            return (return_value, enum_value)
        if lower_enum_value.startswith(lower_value):
            prefix_matches.append((return_value, enum_value))

    if len(prefix_matches) == 0:
        command._raise_argument_validation_exception(typedef, value,
                'unexpected value for enum', enum_values.keys())

    return prefix_matches