diff --git a/hooks/config.py b/hooks/config.py index 9917ec5..539c085 100644 --- a/hooks/config.py +++ b/hooks/config.py @@ -1,4 +1,6 @@ +from errors import InvalidUpdate from git import git +from type_conversions import to_type # A dictionary of all git config names that this module can query. # - The key used for this table is the config name. @@ -57,8 +59,28 @@ def git_config(option_name): if __git_config_map is None: initialize_git_config_map() + val = __git_config_map[option_name] - return __git_config_map[option_name] + # If this option as a 'type' specified, then convert it to + # this type if necessary. We do this here, rather than during + # initialize_git_config_map to avoid the potential for causing + # an error for options which might not be used in the end. + if ('type' in GIT_CONFIG_OPTS[option_name] and isinstance(val, str)): + try: + val = to_type(val, GIT_CONFIG_OPTS[option_name]['type']) + except ValueError: + TYPE_NAME_MAP = {bool: 'boolean', + int: 'integer', + } + type_name = TYPE_NAME_MAP[GIT_CONFIG_OPTS[option_name]['type']] + raise InvalidUpdate( + 'Invalid %s value: %s (must be %s)' + % (option_name, val, type_name)) + # Save the converted value to avoid having to do it again + # the next time we query the same config option. + __git_config_map[option_name] = val + + return val def initialize_git_config_map(): diff --git a/hooks/type_conversions.py b/hooks/type_conversions.py new file mode 100644 index 0000000..91459b9 --- /dev/null +++ b/hooks/type_conversions.py @@ -0,0 +1,48 @@ +"""A number of utility functions performing type conversions... +""" + + +def to_bool(val): + """Translate val into a either True or False. + + Raise ValueError if val cannot be converted. + + PARAMETERS + val: The value to convert. It can be either a boolean, + in which case this function is a no-op, or a string + whose (lowercase) value must then be either 'true' + or 'false'. + + REMARKS + It would be nice if we could have used the bool builtin + function, but this function unfortunately returns something + different: It applies the truth test on the argument, and + then returns the result of that test. In other words, + bool("False") returns True! + """ + if val in (True, False): + return val + val_str = str(val).lower() + if val_str == 'true': + return True + if val_str == 'false': + return False + raise ValueError("invalid boolean value: '%s'", str(val)) + + +def to_type(val, new_type): + """Translate val to the given type. + + Raise ValueError if val cannot be converted. + + PARAMETERS + val: The value to convert. + new_type: A callable that indicates the new type for the value. + Usually one of the built-in functions such as 'int', or + 'bool', etc. + """ + # Most of the built-ins perform a translation job, but there + # are some exceptions... + if new_type == bool: + new_type = to_bool + return new_type(val)