17423c01aSMichael Walsh#!/usr/bin/env python 27423c01aSMichael Walsh 37423c01aSMichael Walshr""" 4018e25fbSMichael WalshThis module provides validation functions like valid_value(), valid_integer(), 5018e25fbSMichael Walshetc. 67423c01aSMichael Walsh""" 77423c01aSMichael Walsh 878bdfdd6SMichael Walshimport os 9*be3a8150SMichael Walshimport re 107423c01aSMichael Walshimport gen_print as gp 11*be3a8150SMichael Walshimport gen_cmd as gc 12018e25fbSMichael Walshimport func_args as fa 137423c01aSMichael Walsh 14e23b5ad3SMichael Walshexit_on_error = False 15e23b5ad3SMichael Walsh 16e23b5ad3SMichael Walsh 17e23b5ad3SMichael Walshdef set_exit_on_error(value): 18e23b5ad3SMichael Walsh r""" 19e23b5ad3SMichael Walsh Set the exit_on_error value to either True or False. 20e23b5ad3SMichael Walsh 21018e25fbSMichael Walsh If exit_on_error is set, validation functions like valid_value() will exit 22e23b5ad3SMichael Walsh the program on error instead of returning False. 23e23b5ad3SMichael Walsh 24e23b5ad3SMichael Walsh Description of argument(s): 25e23b5ad3SMichael Walsh value Value to set global exit_on_error to. 26e23b5ad3SMichael Walsh """ 27e23b5ad3SMichael Walsh 28e23b5ad3SMichael Walsh global exit_on_error 29e23b5ad3SMichael Walsh exit_on_error = value 30e23b5ad3SMichael Walsh 31e23b5ad3SMichael Walsh 32018e25fbSMichael Walshdef get_var_name(*args, **kwargs): 33e23b5ad3SMichael Walsh r""" 34018e25fbSMichael Walsh If args/kwargs contain a var_name, simply return its value. Otherwise, 35018e25fbSMichael Walsh get the variable name of the first argument used to call the validation 36018e25fbSMichael Walsh function (e.g. valid, valid_integer, etc.) and return it. 37e23b5ad3SMichael Walsh 38e23b5ad3SMichael Walsh This function is designed solely for use by other functions in this file. 39e23b5ad3SMichael Walsh 40e23b5ad3SMichael Walsh Example: 41e23b5ad3SMichael Walsh 42e23b5ad3SMichael Walsh A programmer codes this: 43e23b5ad3SMichael Walsh 44e23b5ad3SMichael Walsh valid_value(last_name) 45e23b5ad3SMichael Walsh 46e23b5ad3SMichael Walsh Which results in the following call stack: 47e23b5ad3SMichael Walsh 48e23b5ad3SMichael Walsh valid_value(last_name) 49e23b5ad3SMichael Walsh -> get_var_name(var_name) 50e23b5ad3SMichael Walsh 51e23b5ad3SMichael Walsh In this example, this function will return "last_name". 52e23b5ad3SMichael Walsh 53e23b5ad3SMichael Walsh Example: 54e23b5ad3SMichael Walsh 55018e25fbSMichael Walsh err_msg = valid_value(last_name, var_name="some_other_name") 56e23b5ad3SMichael Walsh 57e23b5ad3SMichael Walsh Which results in the following call stack: 58e23b5ad3SMichael Walsh 59018e25fbSMichael Walsh valid_value(var_value, var_name="some_other_name") 60e23b5ad3SMichael Walsh -> get_var_name(var_name) 61e23b5ad3SMichael Walsh 62e23b5ad3SMichael Walsh In this example, this function will return "some_other_name". 63e23b5ad3SMichael Walsh 64e23b5ad3SMichael Walsh Description of argument(s): 65e23b5ad3SMichael Walsh var_name The name of the variable. 66e23b5ad3SMichael Walsh """ 67e23b5ad3SMichael Walsh 68018e25fbSMichael Walsh var_name, args, kwargs = fa.pop_arg(*args, **kwargs) 69018e25fbSMichael Walsh if var_name: 70e23b5ad3SMichael Walsh return var_name 71018e25fbSMichael Walsh return gp.get_arg_name(0, 1, stack_frame_ix=3) 72e23b5ad3SMichael Walsh 73e23b5ad3SMichael Walsh 74e23b5ad3SMichael Walshdef process_error_message(error_message): 75e23b5ad3SMichael Walsh r""" 76018e25fbSMichael Walsh Process the error_message in the manner described below. 77e23b5ad3SMichael Walsh 78018e25fbSMichael Walsh This function is designed solely for use by other functions in this file. 79018e25fbSMichael Walsh 80018e25fbSMichael Walsh NOTE: A blank error_message means that there is no error. 81018e25fbSMichael Walsh 82018e25fbSMichael Walsh For the following explanations, assume the caller of this function is a 83018e25fbSMichael Walsh function with the following definition: 84018e25fbSMichael Walsh valid_value(var_value, valid_values=[], invalid_values=[], *args, 85018e25fbSMichael Walsh **kwargs): 86018e25fbSMichael Walsh 87018e25fbSMichael Walsh If the user of valid_value() is assigning the valid_value() return value 88018e25fbSMichael Walsh to a variable, process_error_message() will simply return the 89018e25fbSMichael Walsh error_message. This mode of usage is illustrated by the following example: 90018e25fbSMichael Walsh 91018e25fbSMichael Walsh error_message = valid_value(var1) 92018e25fbSMichael Walsh 93018e25fbSMichael Walsh This mode is useful for callers who wish to validate a variable and then 94018e25fbSMichael Walsh decide for themselves what to do with the error_message (e.g. 95018e25fbSMichael Walsh raise(error_message), BuiltIn().fail(error_message), etc.). 96018e25fbSMichael Walsh 97018e25fbSMichael Walsh If the user of valid_value() is NOT assigning the valid_value() return 98018e25fbSMichael Walsh value to a variable, process_error_message() will behave as follows. 99018e25fbSMichael Walsh 100018e25fbSMichael Walsh First, if error_message is non-blank, it will be printed to stderr via a 101018e25fbSMichael Walsh call to gp.print_error_report(error_message). 102018e25fbSMichael Walsh 103018e25fbSMichael Walsh If exit_on_error is set: 104018e25fbSMichael Walsh - If the error_message is blank, simply return. 105018e25fbSMichael Walsh - If the error_message is non-blank, exit the program with a return code 106018e25fbSMichael Walsh of 1. 107018e25fbSMichael Walsh 108018e25fbSMichael Walsh If exit_on_error is NOT set: 109018e25fbSMichael Walsh - If the error_message is blank, return True. 110018e25fbSMichael Walsh - If the error_message is non-blank, return False. 111e23b5ad3SMichael Walsh 112e23b5ad3SMichael Walsh Description of argument(s): 113e23b5ad3SMichael Walsh error_message An error message. 114e23b5ad3SMichael Walsh """ 115e23b5ad3SMichael Walsh 116018e25fbSMichael Walsh # Determine whether the caller's caller is assigning the result to a 117018e25fbSMichael Walsh # variable. 118018e25fbSMichael Walsh l_value = gp.get_arg_name(None, -1, stack_frame_ix=3) 119018e25fbSMichael Walsh if l_value: 120018e25fbSMichael Walsh return error_message 121018e25fbSMichael Walsh 122e23b5ad3SMichael Walsh if error_message == "": 123018e25fbSMichael Walsh if exit_on_error: 124018e25fbSMichael Walsh return 125e23b5ad3SMichael Walsh return True 126e23b5ad3SMichael Walsh 127018e25fbSMichael Walsh gp.print_error_report(error_message, stack_frame_ix=4) 128e23b5ad3SMichael Walsh if exit_on_error: 12910a4d98bSMichael Walsh exit(1) 130e23b5ad3SMichael Walsh return False 131e23b5ad3SMichael Walsh 1327423c01aSMichael Walsh 133018e25fbSMichael Walsh# Note to programmers: All of the validation functions in this module should 134018e25fbSMichael Walsh# follow the same basic template: 135018e25fbSMichael Walsh# def valid_value(var_value, var1, var2, varn, *args, **kwargs): 136018e25fbSMichael Walsh# 137018e25fbSMichael Walsh# error_message = "" 138018e25fbSMichael Walsh# if not valid: 139018e25fbSMichael Walsh# var_name = get_var_name(*args, **kwargs) 140018e25fbSMichael Walsh# error_message += "The following variable is invalid because...:\n" 141018e25fbSMichael Walsh# error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 142018e25fbSMichael Walsh# 143018e25fbSMichael Walsh# return process_error_message(error_message) 1447423c01aSMichael Walsh 145018e25fbSMichael Walsh 146018e25fbSMichael Walsh# The docstring header and footer will be added to each validation function's 147018e25fbSMichael Walsh# existing docstring. 148018e25fbSMichael Walshdocstring_header = \ 149018e25fbSMichael Walsh r""" 150018e25fbSMichael Walsh Determine whether var_value is valid, construct an error_message and call 151018e25fbSMichael Walsh process_error_message(error_message). 152018e25fbSMichael Walsh 153018e25fbSMichael Walsh See the process_error_message() function defined in this module for a 154018e25fbSMichael Walsh description of how error messages are processed. 1557423c01aSMichael Walsh """ 1567423c01aSMichael Walsh 157018e25fbSMichael Walshadditional_args_docstring_footer = \ 158018e25fbSMichael Walsh r""" 159018e25fbSMichael Walsh args Additional positional arguments (described 160018e25fbSMichael Walsh below). 161018e25fbSMichael Walsh kwargs Additional keyword arguments (described 162018e25fbSMichael Walsh below). 163018e25fbSMichael Walsh 164018e25fbSMichael Walsh Additional argument(s): 165018e25fbSMichael Walsh var_name The name of the variable whose value is 166018e25fbSMichael Walsh passed in var_value. For the general 167018e25fbSMichael Walsh case, this argument is unnecessary as this 168018e25fbSMichael Walsh function can figure out the var_name. 169018e25fbSMichael Walsh This is provided for Robot callers in 170018e25fbSMichael Walsh which case, this function lacks the 171018e25fbSMichael Walsh ability to determine the variable name. 172018e25fbSMichael Walsh """ 173018e25fbSMichael Walsh 174018e25fbSMichael Walsh 175018e25fbSMichael Walshdef valid_type(var_value, required_type, *args, **kwargs): 176018e25fbSMichael Walsh r""" 177018e25fbSMichael Walsh The variable value is valid if it is of the required type. 178018e25fbSMichael Walsh 179018e25fbSMichael Walsh Examples: 180018e25fbSMichael Walsh 181018e25fbSMichael Walsh valid_type(var1, int) 182018e25fbSMichael Walsh 183018e25fbSMichael Walsh valid_type(var1, (list, dict)) 184018e25fbSMichael Walsh 185018e25fbSMichael Walsh Description of argument(s): 186018e25fbSMichael Walsh var_value The value being validated. 187018e25fbSMichael Walsh required_type A type or a tuple of types (e.g. str, int, 188018e25fbSMichael Walsh etc.). 189018e25fbSMichael Walsh """ 190018e25fbSMichael Walsh 191018e25fbSMichael Walsh error_message = "" 192018e25fbSMichael Walsh if type(required_type) is tuple: 193018e25fbSMichael Walsh if type(var_value) in required_type: 194018e25fbSMichael Walsh return process_error_message(error_message) 195018e25fbSMichael Walsh else: 196018e25fbSMichael Walsh if type(var_value) is required_type: 197018e25fbSMichael Walsh return process_error_message(error_message) 198018e25fbSMichael Walsh 199018e25fbSMichael Walsh # If we get to this point, the validation has failed. 200018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 201018e25fbSMichael Walsh error_message += "Invalid variable type:\n" 202018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 203018e25fbSMichael Walsh gp.blank() | gp.show_type()) 204018e25fbSMichael Walsh error_message += "\n" 205018e25fbSMichael Walsh error_message += gp.sprint_var(required_type) 206018e25fbSMichael Walsh 207018e25fbSMichael Walsh return process_error_message(error_message) 208018e25fbSMichael Walsh 209018e25fbSMichael Walsh 210018e25fbSMichael Walshdef valid_value(var_value, valid_values=[], invalid_values=[], *args, 211018e25fbSMichael Walsh **kwargs): 212018e25fbSMichael Walsh 213018e25fbSMichael Walsh r""" 214018e25fbSMichael Walsh The variable value is valid if it is either contained in the valid_values 215018e25fbSMichael Walsh list or if it is NOT contained in the invalid_values list. If the caller 216018e25fbSMichael Walsh specifies nothing for either of these 2 arguments, invalid_values will be 217018e25fbSMichael Walsh initialized to ['', None]. This is a good way to fail on variables which 218018e25fbSMichael Walsh contain blank values. 219018e25fbSMichael Walsh 220018e25fbSMichael Walsh It is illegal to specify both valid_values and invalid values. 221018e25fbSMichael Walsh 222018e25fbSMichael Walsh Example: 223018e25fbSMichael Walsh 224018e25fbSMichael Walsh var1 = '' 225018e25fbSMichael Walsh valid_value(var1) 226018e25fbSMichael Walsh 227018e25fbSMichael Walsh This code would fail because var1 is blank and the default value for 228018e25fbSMichael Walsh invalid_values is ['', None]. 229018e25fbSMichael Walsh 230018e25fbSMichael Walsh Example: 231018e25fbSMichael Walsh var1 = 'yes' 232018e25fbSMichael Walsh valid_value(var1, valid_values=['yes', 'true']) 233018e25fbSMichael Walsh 234018e25fbSMichael Walsh This code would pass. 235018e25fbSMichael Walsh 236018e25fbSMichael Walsh Description of argument(s): 237018e25fbSMichael Walsh var_value The value being validated. 238018e25fbSMichael Walsh valid_values A list of valid values. The variable 239018e25fbSMichael Walsh value must be equal to one of these values 240018e25fbSMichael Walsh to be considered valid. 241018e25fbSMichael Walsh invalid_values A list of invalid values. If the variable 242018e25fbSMichael Walsh value is equal to any of these, it is 243018e25fbSMichael Walsh considered invalid. 244018e25fbSMichael Walsh """ 245018e25fbSMichael Walsh 246bec416ddSMichael Walsh error_message = "" 247bec416ddSMichael Walsh 248e23b5ad3SMichael Walsh # Validate this function's arguments. 2497423c01aSMichael Walsh len_valid_values = len(valid_values) 2507423c01aSMichael Walsh len_invalid_values = len(invalid_values) 2517423c01aSMichael Walsh if len_valid_values > 0 and len_invalid_values > 0: 252018e25fbSMichael Walsh error_message += "Programmer error - You must provide either an" 253018e25fbSMichael Walsh error_message += " invalid_values list or a valid_values" 254018e25fbSMichael Walsh error_message += " list but NOT both:\n" 255018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values) 256018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values) 257018e25fbSMichael Walsh return process_error_message(error_message) 2587423c01aSMichael Walsh 2597423c01aSMichael Walsh if len_valid_values > 0: 2607423c01aSMichael Walsh # Processing the valid_values list. 2617423c01aSMichael Walsh if var_value in valid_values: 262018e25fbSMichael Walsh return process_error_message(error_message) 263018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 264018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 265018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 266018e25fbSMichael Walsh gp.blank() | gp.verbose() 267018e25fbSMichael Walsh | gp.show_type()) 268018e25fbSMichael Walsh error_message += "\n" 269018e25fbSMichael Walsh error_message += "It must be one of the following values:\n" 270018e25fbSMichael Walsh error_message += "\n" 271018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values, 272018e25fbSMichael Walsh gp.blank() | gp.show_type()) 273018e25fbSMichael Walsh return process_error_message(error_message) 2747423c01aSMichael Walsh 2757423c01aSMichael Walsh if len_invalid_values == 0: 276bec416ddSMichael Walsh # Assign default value. 277018e25fbSMichael Walsh invalid_values = ["", None] 2787423c01aSMichael Walsh 2797423c01aSMichael Walsh # Assertion: We have an invalid_values list. Processing it now. 2807423c01aSMichael Walsh if var_value not in invalid_values: 281018e25fbSMichael Walsh return process_error_message(error_message) 282bec416ddSMichael Walsh 283018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 284018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 285018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 286018e25fbSMichael Walsh gp.blank() | gp.verbose() 287018e25fbSMichael Walsh | gp.show_type()) 288018e25fbSMichael Walsh error_message += "\n" 289018e25fbSMichael Walsh error_message += "It must NOT be one of the following values:\n" 290018e25fbSMichael Walsh error_message += "\n" 291018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values, 292018e25fbSMichael Walsh gp.blank() | gp.show_type()) 293e23b5ad3SMichael Walsh return process_error_message(error_message) 2947423c01aSMichael Walsh 295bec416ddSMichael Walsh 296018e25fbSMichael Walshdef valid_range(var_value, lower=None, upper=None, *args, **kwargs): 297bec416ddSMichael Walsh r""" 298018e25fbSMichael Walsh The variable value is valid if it is within the specified range. 299bec416ddSMichael Walsh 300018e25fbSMichael Walsh This function can be used with any type of operands where they can have a 301018e25fbSMichael Walsh greater than/less than relationship to each other (e.g. int, float, str). 302018e25fbSMichael Walsh 303018e25fbSMichael Walsh Description of argument(s): 304bec416ddSMichael Walsh var_value The value being validated. 305018e25fbSMichael Walsh lower The lower end of the range. If not None, 306018e25fbSMichael Walsh the var_value must be greater than or 307018e25fbSMichael Walsh equal to lower. 308018e25fbSMichael Walsh upper The upper end of the range. If not None, 309018e25fbSMichael Walsh the var_value must be less than or equal 310018e25fbSMichael Walsh to upper. 311bec416ddSMichael Walsh """ 312bec416ddSMichael Walsh 313bec416ddSMichael Walsh error_message = "" 314018e25fbSMichael Walsh if not lower and not upper: 315018e25fbSMichael Walsh return process_error_message(error_message) 316018e25fbSMichael Walsh if not lower and var_value <= upper: 317018e25fbSMichael Walsh return process_error_message(error_message) 318018e25fbSMichael Walsh if not upper and var_value >= lower: 319018e25fbSMichael Walsh return process_error_message(error_message) 320018e25fbSMichael Walsh if lower and upper: 321018e25fbSMichael Walsh if lower > upper: 322018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 323018e25fbSMichael Walsh error_message += "Programmer error - the lower value is greater" 324018e25fbSMichael Walsh error_message += " than the upper value:\n" 325018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type()) 326018e25fbSMichael Walsh return process_error_message(error_message) 327018e25fbSMichael Walsh if lower <= var_value <= upper: 328018e25fbSMichael Walsh return process_error_message(error_message) 329bec416ddSMichael Walsh 330018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 331018e25fbSMichael Walsh error_message += "The following variable is not within the expected" 332018e25fbSMichael Walsh error_message += " range:\n" 333018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 334018e25fbSMichael Walsh error_message += "\n" 335018e25fbSMichael Walsh error_message += "range:\n" 336018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2) 337e23b5ad3SMichael Walsh return process_error_message(error_message) 3387423c01aSMichael Walsh 33978bdfdd6SMichael Walsh 340018e25fbSMichael Walshdef valid_integer(var_value, lower=None, upper=None, *args, **kwargs): 34178bdfdd6SMichael Walsh r""" 342018e25fbSMichael Walsh The variable value is valid if it is an integer or can be interpreted as 343018e25fbSMichael Walsh an integer (e.g. 7, "7", etc.). 34478bdfdd6SMichael Walsh 345018e25fbSMichael Walsh This function also calls valid_range to make sure the integer value is 346018e25fbSMichael Walsh within the specified range (if any). 347018e25fbSMichael Walsh 348018e25fbSMichael Walsh Description of argument(s): 34978bdfdd6SMichael Walsh var_value The value being validated. 350018e25fbSMichael Walsh lower The lower end of the range. If not None, 351018e25fbSMichael Walsh the var_value must be greater than or 352018e25fbSMichael Walsh equal to lower. 353018e25fbSMichael Walsh upper The upper end of the range. If not None, 354018e25fbSMichael Walsh the var_value must be less than or equal 355018e25fbSMichael Walsh to upper. 356018e25fbSMichael Walsh """ 357018e25fbSMichael Walsh 358018e25fbSMichael Walsh error_message = "" 359018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 360018e25fbSMichael Walsh try: 361018e25fbSMichael Walsh var_value = int(str(var_value), 0) 362018e25fbSMichael Walsh except ValueError: 363018e25fbSMichael Walsh error_message += "Invalid integer value:\n" 364018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 365018e25fbSMichael Walsh gp.blank() | gp.show_type()) 366018e25fbSMichael Walsh return process_error_message(error_message) 367018e25fbSMichael Walsh 368018e25fbSMichael Walsh # Check the range (if any). 369018e25fbSMichael Walsh if lower: 370018e25fbSMichael Walsh lower = int(str(lower), 0) 371018e25fbSMichael Walsh if upper: 372018e25fbSMichael Walsh upper = int(str(upper), 0) 373018e25fbSMichael Walsh error_message = valid_range(var_value, lower, upper, var_name=var_name) 374018e25fbSMichael Walsh 375018e25fbSMichael Walsh return process_error_message(error_message) 376018e25fbSMichael Walsh 377018e25fbSMichael Walsh 378018e25fbSMichael Walshdef valid_dir_path(var_value, *args, **kwargs): 379018e25fbSMichael Walsh r""" 380018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing 381018e25fbSMichael Walsh directory. 382018e25fbSMichael Walsh 383018e25fbSMichael Walsh Description of argument(s): 384018e25fbSMichael Walsh var_value The value being validated. 38578bdfdd6SMichael Walsh """ 38678bdfdd6SMichael Walsh 38778bdfdd6SMichael Walsh error_message = "" 38878bdfdd6SMichael Walsh if not os.path.isdir(str(var_value)): 389018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 390018e25fbSMichael Walsh error_message += "The following directory does not exist:\n" 391018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value) 39278bdfdd6SMichael Walsh 393e23b5ad3SMichael Walsh return process_error_message(error_message) 39478bdfdd6SMichael Walsh 39578bdfdd6SMichael Walsh 396018e25fbSMichael Walshdef valid_file_path(var_value, *args, **kwargs): 39778bdfdd6SMichael Walsh r""" 398018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing file. 39978bdfdd6SMichael Walsh 400018e25fbSMichael Walsh Description of argument(s): 40178bdfdd6SMichael Walsh var_value The value being validated. 40278bdfdd6SMichael Walsh """ 40378bdfdd6SMichael Walsh 40478bdfdd6SMichael Walsh error_message = "" 40578bdfdd6SMichael Walsh if not os.path.isfile(str(var_value)): 406018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 407018e25fbSMichael Walsh error_message += "The following file does not exist:\n" 408018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value) 40978bdfdd6SMichael Walsh 410e23b5ad3SMichael Walsh return process_error_message(error_message) 41178bdfdd6SMichael Walsh 41278bdfdd6SMichael Walsh 413018e25fbSMichael Walshdef valid_path(var_value, *args, **kwargs): 414e23b5ad3SMichael Walsh r""" 415018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing file or 416018e25fbSMichael Walsh directory. 417e23b5ad3SMichael Walsh 418018e25fbSMichael Walsh Description of argument(s): 419e23b5ad3SMichael Walsh var_value The value being validated. 420e23b5ad3SMichael Walsh """ 421e23b5ad3SMichael Walsh 422e23b5ad3SMichael Walsh error_message = "" 423e23b5ad3SMichael Walsh if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))): 424018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 425018e25fbSMichael Walsh error_message += "Invalid path (file or directory does not exist):\n" 426018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value) 427e23b5ad3SMichael Walsh 428e23b5ad3SMichael Walsh return process_error_message(error_message) 4292c687e98SMichael Walsh 4302c687e98SMichael Walsh 43135026be5SMichael Walshdef valid_list(var_value, valid_values=[], invalid_values=[], 43235026be5SMichael Walsh required_values=[], fail_on_empty=False, *args, **kwargs): 4332c687e98SMichael Walsh r""" 434018e25fbSMichael Walsh The variable value is valid if it is a list where each entry can be found 43535026be5SMichael Walsh in the valid_values list or if none of its values can be found in the 43635026be5SMichael Walsh invalid_values list or if all of the values in the required_values list 43735026be5SMichael Walsh can be found in var_value. 43835026be5SMichael Walsh 43935026be5SMichael Walsh The caller may only specify one of these 3 arguments: valid_values, 44035026be5SMichael Walsh invalid_values, required_values. 4412c687e98SMichael Walsh 442018e25fbSMichael Walsh Description of argument(s): 443018e25fbSMichael Walsh var_value The value being validated. 444ca193993SMichael Walsh valid_values A list of valid values. Each element in 445ca193993SMichael Walsh the var_value list must be equal to one of 446ca193993SMichael Walsh these values to be considered valid. 44735026be5SMichael Walsh invalid_values A list of invalid values. If any element 44835026be5SMichael Walsh in var_value is equal to any of the values 44935026be5SMichael Walsh in this argument, var_value is considered 45035026be5SMichael Walsh invalid. 45135026be5SMichael Walsh required_values Every value in required_values must be 45235026be5SMichael Walsh found in var_value. Otherwise, var_value 45335026be5SMichael Walsh is considered invalid. 454018e25fbSMichael Walsh fail_on_empty Indicates that an empty list for the 455018e25fbSMichael Walsh variable value should be considered an 456018e25fbSMichael Walsh error. 457ca193993SMichael Walsh """ 458ca193993SMichael Walsh 459ca193993SMichael Walsh error_message = "" 460018e25fbSMichael Walsh 46135026be5SMichael Walsh # Validate this function's arguments. 46235026be5SMichael Walsh len_valid_values = len(valid_values) 46335026be5SMichael Walsh len_invalid_values = len(invalid_values) 46435026be5SMichael Walsh len_required_values = len(required_values) 46535026be5SMichael Walsh if (len_valid_values + len_invalid_values + len_required_values) > 1: 46635026be5SMichael Walsh error_message += "Programmer error - You must provide only one of the" 46735026be5SMichael Walsh error_message += " following: valid_values, invalid_values," 46835026be5SMichael Walsh error_message += " required_values.\n" 46935026be5SMichael Walsh error_message += gp.sprint_var(invalid_values) 47035026be5SMichael Walsh error_message += gp.sprint_var(valid_values) 47135026be5SMichael Walsh error_message += gp.sprint_var(required_values) 47235026be5SMichael Walsh return process_error_message(error_message) 47335026be5SMichael Walsh 474018e25fbSMichael Walsh if type(var_value) is not list: 475018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 476018e25fbSMichael Walsh error_message = valid_type(var_value, list, var_name=var_name) 477018e25fbSMichael Walsh if error_message: 478018e25fbSMichael Walsh return process_error_message(error_message) 479018e25fbSMichael Walsh 480018e25fbSMichael Walsh if fail_on_empty and len(var_value) == 0: 481018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 482018e25fbSMichael Walsh error_message += "Invalid empty list:\n" 483018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 484018e25fbSMichael Walsh return process_error_message(error_message) 485ca193993SMichael Walsh 48635026be5SMichael Walsh if len(required_values): 48735026be5SMichael Walsh found_error = 0 48835026be5SMichael Walsh display_required_values = list(required_values) 48935026be5SMichael Walsh for ix in range(0, len(required_values)): 49035026be5SMichael Walsh if required_values[ix] not in var_value: 49135026be5SMichael Walsh found_error = 1 49235026be5SMichael Walsh display_required_values[ix] = \ 49335026be5SMichael Walsh str(display_required_values[ix]) + "*" 49435026be5SMichael Walsh if found_error: 49535026be5SMichael Walsh var_name = get_var_name(*args, **kwargs) 49635026be5SMichael Walsh error_message += "The following list is invalid:\n" 49735026be5SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 49835026be5SMichael Walsh gp.blank() | gp.show_type()) 49935026be5SMichael Walsh error_message += "\n" 50035026be5SMichael Walsh error_message += "Because some of the values in the " 50135026be5SMichael Walsh error_message += "required_values list are not present (see" 50235026be5SMichael Walsh error_message += " entries marked with \"*\"):\n" 50335026be5SMichael Walsh error_message += "\n" 50435026be5SMichael Walsh error_message += gp.sprint_varx('required_values', 50535026be5SMichael Walsh display_required_values, 50635026be5SMichael Walsh gp.blank() | gp.show_type()) 50735026be5SMichael Walsh error_message += "\n" 50835026be5SMichael Walsh 50935026be5SMichael Walsh return process_error_message(error_message) 51035026be5SMichael Walsh 51135026be5SMichael Walsh if len(invalid_values): 51235026be5SMichael Walsh found_error = 0 51335026be5SMichael Walsh display_var_value = list(var_value) 51435026be5SMichael Walsh for ix in range(0, len(var_value)): 51535026be5SMichael Walsh if var_value[ix] in invalid_values: 51635026be5SMichael Walsh found_error = 1 51735026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 51835026be5SMichael Walsh 51935026be5SMichael Walsh if found_error: 52035026be5SMichael Walsh var_name = get_var_name(*args, **kwargs) 52135026be5SMichael Walsh error_message += "The following list is invalid (see entries" 52235026be5SMichael Walsh error_message += " marked with \"*\"):\n" 52335026be5SMichael Walsh error_message += gp.sprint_varx(var_name, display_var_value, 52435026be5SMichael Walsh gp.blank() | gp.show_type()) 52535026be5SMichael Walsh error_message += "\n" 52635026be5SMichael Walsh error_message += gp.sprint_var(invalid_values, gp.show_type()) 52735026be5SMichael Walsh return process_error_message(error_message) 52835026be5SMichael Walsh 529ca193993SMichael Walsh found_error = 0 530ca193993SMichael Walsh display_var_value = list(var_value) 531ca193993SMichael Walsh for ix in range(0, len(var_value)): 532ca193993SMichael Walsh if var_value[ix] not in valid_values: 533ca193993SMichael Walsh found_error = 1 53435026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 535ca193993SMichael Walsh 536ca193993SMichael Walsh if found_error: 537018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 538018e25fbSMichael Walsh error_message += "The following list is invalid (see entries marked" 539018e25fbSMichael Walsh error_message += " with \"*\"):\n" 540018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, display_var_value, 541018e25fbSMichael Walsh gp.blank() | gp.show_type()) 542018e25fbSMichael Walsh error_message += "\n" 54335026be5SMichael Walsh error_message += gp.sprint_var(valid_values, gp.show_type()) 544018e25fbSMichael Walsh return process_error_message(error_message) 545ca193993SMichael Walsh 546ca193993SMichael Walsh return process_error_message(error_message) 5477ac5fd81SMichael Walsh 5487ac5fd81SMichael Walsh 549018e25fbSMichael Walshdef valid_dict(var_value, required_keys=[], *args, **kwargs): 5507ac5fd81SMichael Walsh r""" 551018e25fbSMichael Walsh The variable value is valid if it is a dictionary containing all of the 552018e25fbSMichael Walsh required keys. 5537ac5fd81SMichael Walsh 554018e25fbSMichael Walsh Description of argument(s): 555018e25fbSMichael Walsh var_value The value being validated. 5567ac5fd81SMichael Walsh required_keys A list of keys which must be found in the 5577ac5fd81SMichael Walsh dictionary for it to be considered valid. 5587ac5fd81SMichael Walsh """ 5597ac5fd81SMichael Walsh 5607ac5fd81SMichael Walsh error_message = "" 561018e25fbSMichael Walsh missing_keys = list(set(required_keys) - set(var_value.keys())) 562018e25fbSMichael Walsh if len(missing_keys) > 0: 563018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 564018e25fbSMichael Walsh error_message += "The following dictionary is invalid because it is" 565018e25fbSMichael Walsh error_message += " missing required keys:\n" 566018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 567018e25fbSMichael Walsh gp.blank() | gp.show_type()) 568018e25fbSMichael Walsh error_message += "\n" 56935026be5SMichael Walsh error_message += gp.sprint_var(missing_keys, gp.show_type()) 5707ac5fd81SMichael Walsh return process_error_message(error_message) 571018e25fbSMichael Walsh 572018e25fbSMichael Walsh 573*be3a8150SMichael Walshdef valid_program(var_value, *args, **kwargs): 574*be3a8150SMichael Walsh r""" 575*be3a8150SMichael Walsh The variable value is valid if it contains the name of a program which can 576*be3a8150SMichael Walsh be located using the "which" command. 577*be3a8150SMichael Walsh 578*be3a8150SMichael Walsh Description of argument(s): 579*be3a8150SMichael Walsh var_value The value being validated. 580*be3a8150SMichael Walsh """ 581*be3a8150SMichael Walsh 582*be3a8150SMichael Walsh error_message = "" 583*be3a8150SMichael Walsh rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0, 584*be3a8150SMichael Walsh ignore_err=1) 585*be3a8150SMichael Walsh if rc: 586*be3a8150SMichael Walsh var_name = get_var_name(*args, **kwargs) 587*be3a8150SMichael Walsh error_message += "The following required program could not be found" 588*be3a8150SMichael Walsh error_message += " using the $PATH environment variable:\n" 589*be3a8150SMichael Walsh error_message += gp.sprint_varx(var_name, var_value) 590*be3a8150SMichael Walsh PATH = os.environ.get("PATH", "").split(":") 591*be3a8150SMichael Walsh error_message += "\n" 592*be3a8150SMichael Walsh error_message += gp.sprint_var(PATH) 593*be3a8150SMichael Walsh return process_error_message(error_message) 594*be3a8150SMichael Walsh 595*be3a8150SMichael Walsh 596018e25fbSMichael Walsh# Modify selected function docstrings by adding headers/footers. 597018e25fbSMichael Walsh 598018e25fbSMichael Walshfunc_names = [ 599018e25fbSMichael Walsh "valid_type", "valid_value", "valid_range", "valid_integer", 600018e25fbSMichael Walsh "valid_dir_path", "valid_file_path", "valid_path", "valid_list", 601*be3a8150SMichael Walsh "valid_dict", "valid_program" 602018e25fbSMichael Walsh] 603018e25fbSMichael Walsh 604018e25fbSMichael Walshraw_doc_strings = {} 605018e25fbSMichael Walsh 606018e25fbSMichael Walshfor func_name in func_names: 607018e25fbSMichael Walsh cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name 608018e25fbSMichael Walsh cmd_buf += ".__doc__" 609018e25fbSMichael Walsh exec(cmd_buf) 610018e25fbSMichael Walsh cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name 611018e25fbSMichael Walsh cmd_buf += ".__doc__.rstrip(\" \\n\") + additional_args_docstring_footer" 612018e25fbSMichael Walsh exec(cmd_buf) 613