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 97423c01aSMichael Walshimport gen_print as gp 10be3a8150SMichael Walshimport gen_cmd as gc 11018e25fbSMichael Walshimport func_args as fa 127423c01aSMichael Walsh 13e23b5ad3SMichael Walshexit_on_error = False 14e23b5ad3SMichael Walsh 15e23b5ad3SMichael Walsh 16e23b5ad3SMichael Walshdef set_exit_on_error(value): 17e23b5ad3SMichael Walsh r""" 18e23b5ad3SMichael Walsh Set the exit_on_error value to either True or False. 19e23b5ad3SMichael Walsh 20018e25fbSMichael Walsh If exit_on_error is set, validation functions like valid_value() will exit 21e23b5ad3SMichael Walsh the program on error instead of returning False. 22e23b5ad3SMichael Walsh 23e23b5ad3SMichael Walsh Description of argument(s): 24e23b5ad3SMichael Walsh value Value to set global exit_on_error to. 25e23b5ad3SMichael Walsh """ 26e23b5ad3SMichael Walsh 27e23b5ad3SMichael Walsh global exit_on_error 28e23b5ad3SMichael Walsh exit_on_error = value 29e23b5ad3SMichael Walsh 30e23b5ad3SMichael Walsh 31018e25fbSMichael Walshdef get_var_name(*args, **kwargs): 32e23b5ad3SMichael Walsh r""" 33018e25fbSMichael Walsh If args/kwargs contain a var_name, simply return its value. Otherwise, 34018e25fbSMichael Walsh get the variable name of the first argument used to call the validation 35018e25fbSMichael Walsh function (e.g. valid, valid_integer, etc.) and return it. 36e23b5ad3SMichael Walsh 37e23b5ad3SMichael Walsh This function is designed solely for use by other functions in this file. 38e23b5ad3SMichael Walsh 39e23b5ad3SMichael Walsh Example: 40e23b5ad3SMichael Walsh 41e23b5ad3SMichael Walsh A programmer codes this: 42e23b5ad3SMichael Walsh 43e23b5ad3SMichael Walsh valid_value(last_name) 44e23b5ad3SMichael Walsh 45e23b5ad3SMichael Walsh Which results in the following call stack: 46e23b5ad3SMichael Walsh 47e23b5ad3SMichael Walsh valid_value(last_name) 48e23b5ad3SMichael Walsh -> get_var_name(var_name) 49e23b5ad3SMichael Walsh 50e23b5ad3SMichael Walsh In this example, this function will return "last_name". 51e23b5ad3SMichael Walsh 52e23b5ad3SMichael Walsh Example: 53e23b5ad3SMichael Walsh 54018e25fbSMichael Walsh err_msg = valid_value(last_name, var_name="some_other_name") 55e23b5ad3SMichael Walsh 56e23b5ad3SMichael Walsh Which results in the following call stack: 57e23b5ad3SMichael Walsh 58018e25fbSMichael Walsh valid_value(var_value, var_name="some_other_name") 59e23b5ad3SMichael Walsh -> get_var_name(var_name) 60e23b5ad3SMichael Walsh 61e23b5ad3SMichael Walsh In this example, this function will return "some_other_name". 62e23b5ad3SMichael Walsh 63e23b5ad3SMichael Walsh Description of argument(s): 64e23b5ad3SMichael Walsh var_name The name of the variable. 65e23b5ad3SMichael Walsh """ 66e23b5ad3SMichael Walsh 67018e25fbSMichael Walsh var_name, args, kwargs = fa.pop_arg(*args, **kwargs) 68018e25fbSMichael Walsh if var_name: 69e23b5ad3SMichael Walsh return var_name 70018e25fbSMichael Walsh return gp.get_arg_name(0, 1, stack_frame_ix=3) 71e23b5ad3SMichael Walsh 72e23b5ad3SMichael Walsh 73e23b5ad3SMichael Walshdef process_error_message(error_message): 74e23b5ad3SMichael Walsh r""" 75018e25fbSMichael Walsh Process the error_message in the manner described below. 76e23b5ad3SMichael Walsh 77018e25fbSMichael Walsh This function is designed solely for use by other functions in this file. 78018e25fbSMichael Walsh 79018e25fbSMichael Walsh NOTE: A blank error_message means that there is no error. 80018e25fbSMichael Walsh 81018e25fbSMichael Walsh For the following explanations, assume the caller of this function is a 82018e25fbSMichael Walsh function with the following definition: 83018e25fbSMichael Walsh valid_value(var_value, valid_values=[], invalid_values=[], *args, 84018e25fbSMichael Walsh **kwargs): 85018e25fbSMichael Walsh 86018e25fbSMichael Walsh If the user of valid_value() is assigning the valid_value() return value 87018e25fbSMichael Walsh to a variable, process_error_message() will simply return the 88018e25fbSMichael Walsh error_message. This mode of usage is illustrated by the following example: 89018e25fbSMichael Walsh 90018e25fbSMichael Walsh error_message = valid_value(var1) 91018e25fbSMichael Walsh 92018e25fbSMichael Walsh This mode is useful for callers who wish to validate a variable and then 93018e25fbSMichael Walsh decide for themselves what to do with the error_message (e.g. 94018e25fbSMichael Walsh raise(error_message), BuiltIn().fail(error_message), etc.). 95018e25fbSMichael Walsh 96018e25fbSMichael Walsh If the user of valid_value() is NOT assigning the valid_value() return 97018e25fbSMichael Walsh value to a variable, process_error_message() will behave as follows. 98018e25fbSMichael Walsh 99018e25fbSMichael Walsh First, if error_message is non-blank, it will be printed to stderr via a 100018e25fbSMichael Walsh call to gp.print_error_report(error_message). 101018e25fbSMichael Walsh 102018e25fbSMichael Walsh If exit_on_error is set: 103018e25fbSMichael Walsh - If the error_message is blank, simply return. 104018e25fbSMichael Walsh - If the error_message is non-blank, exit the program with a return code 105018e25fbSMichael Walsh of 1. 106018e25fbSMichael Walsh 107018e25fbSMichael Walsh If exit_on_error is NOT set: 108018e25fbSMichael Walsh - If the error_message is blank, return True. 109018e25fbSMichael Walsh - If the error_message is non-blank, return False. 110e23b5ad3SMichael Walsh 111e23b5ad3SMichael Walsh Description of argument(s): 112e23b5ad3SMichael Walsh error_message An error message. 113e23b5ad3SMichael Walsh """ 114e23b5ad3SMichael Walsh 115018e25fbSMichael Walsh # Determine whether the caller's caller is assigning the result to a 116018e25fbSMichael Walsh # variable. 117018e25fbSMichael Walsh l_value = gp.get_arg_name(None, -1, stack_frame_ix=3) 118018e25fbSMichael Walsh if l_value: 119018e25fbSMichael Walsh return error_message 120018e25fbSMichael Walsh 121e23b5ad3SMichael Walsh if error_message == "": 122018e25fbSMichael Walsh if exit_on_error: 123018e25fbSMichael Walsh return 124e23b5ad3SMichael Walsh return True 125e23b5ad3SMichael Walsh 126018e25fbSMichael Walsh gp.print_error_report(error_message, stack_frame_ix=4) 127e23b5ad3SMichael Walsh if exit_on_error: 12810a4d98bSMichael Walsh exit(1) 129e23b5ad3SMichael Walsh return False 130e23b5ad3SMichael Walsh 1317423c01aSMichael Walsh 132018e25fbSMichael Walsh# Note to programmers: All of the validation functions in this module should 133018e25fbSMichael Walsh# follow the same basic template: 134018e25fbSMichael Walsh# def valid_value(var_value, var1, var2, varn, *args, **kwargs): 135018e25fbSMichael Walsh# 136018e25fbSMichael Walsh# error_message = "" 137018e25fbSMichael Walsh# if not valid: 138018e25fbSMichael Walsh# var_name = get_var_name(*args, **kwargs) 139018e25fbSMichael Walsh# error_message += "The following variable is invalid because...:\n" 140018e25fbSMichael Walsh# error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 141018e25fbSMichael Walsh# 142018e25fbSMichael Walsh# return process_error_message(error_message) 1437423c01aSMichael Walsh 144018e25fbSMichael Walsh 145018e25fbSMichael Walsh# The docstring header and footer will be added to each validation function's 146018e25fbSMichael Walsh# existing docstring. 147018e25fbSMichael Walshdocstring_header = \ 148018e25fbSMichael Walsh r""" 149018e25fbSMichael Walsh Determine whether var_value is valid, construct an error_message and call 150018e25fbSMichael Walsh process_error_message(error_message). 151018e25fbSMichael Walsh 152018e25fbSMichael Walsh See the process_error_message() function defined in this module for a 153018e25fbSMichael Walsh description of how error messages are processed. 1547423c01aSMichael Walsh """ 1557423c01aSMichael Walsh 156018e25fbSMichael Walshadditional_args_docstring_footer = \ 157018e25fbSMichael Walsh r""" 158018e25fbSMichael Walsh args Additional positional arguments (described 159018e25fbSMichael Walsh below). 160018e25fbSMichael Walsh kwargs Additional keyword arguments (described 161018e25fbSMichael Walsh below). 162018e25fbSMichael Walsh 163018e25fbSMichael Walsh Additional argument(s): 164018e25fbSMichael Walsh var_name The name of the variable whose value is 165018e25fbSMichael Walsh passed in var_value. For the general 166018e25fbSMichael Walsh case, this argument is unnecessary as this 167018e25fbSMichael Walsh function can figure out the var_name. 168018e25fbSMichael Walsh This is provided for Robot callers in 169018e25fbSMichael Walsh which case, this function lacks the 170018e25fbSMichael Walsh ability to determine the variable name. 171018e25fbSMichael Walsh """ 172018e25fbSMichael Walsh 173018e25fbSMichael Walsh 174018e25fbSMichael Walshdef valid_type(var_value, required_type, *args, **kwargs): 175018e25fbSMichael Walsh r""" 176018e25fbSMichael Walsh The variable value is valid if it is of the required type. 177018e25fbSMichael Walsh 178018e25fbSMichael Walsh Examples: 179018e25fbSMichael Walsh 180018e25fbSMichael Walsh valid_type(var1, int) 181018e25fbSMichael Walsh 182018e25fbSMichael Walsh valid_type(var1, (list, dict)) 183018e25fbSMichael Walsh 184018e25fbSMichael Walsh Description of argument(s): 185018e25fbSMichael Walsh var_value The value being validated. 186018e25fbSMichael Walsh required_type A type or a tuple of types (e.g. str, int, 187018e25fbSMichael Walsh etc.). 188018e25fbSMichael Walsh """ 189018e25fbSMichael Walsh 190018e25fbSMichael Walsh error_message = "" 191018e25fbSMichael Walsh if type(required_type) is tuple: 192018e25fbSMichael Walsh if type(var_value) in required_type: 193018e25fbSMichael Walsh return process_error_message(error_message) 194018e25fbSMichael Walsh else: 195018e25fbSMichael Walsh if type(var_value) is required_type: 196018e25fbSMichael Walsh return process_error_message(error_message) 197018e25fbSMichael Walsh 198018e25fbSMichael Walsh # If we get to this point, the validation has failed. 199018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 200018e25fbSMichael Walsh error_message += "Invalid variable type:\n" 201018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 202018e25fbSMichael Walsh gp.blank() | gp.show_type()) 203018e25fbSMichael Walsh error_message += "\n" 204018e25fbSMichael Walsh error_message += gp.sprint_var(required_type) 205018e25fbSMichael Walsh 206018e25fbSMichael Walsh return process_error_message(error_message) 207018e25fbSMichael Walsh 208018e25fbSMichael Walsh 209018e25fbSMichael Walshdef valid_value(var_value, valid_values=[], invalid_values=[], *args, 210018e25fbSMichael Walsh **kwargs): 211018e25fbSMichael Walsh 212018e25fbSMichael Walsh r""" 213018e25fbSMichael Walsh The variable value is valid if it is either contained in the valid_values 214018e25fbSMichael Walsh list or if it is NOT contained in the invalid_values list. If the caller 215018e25fbSMichael Walsh specifies nothing for either of these 2 arguments, invalid_values will be 216018e25fbSMichael Walsh initialized to ['', None]. This is a good way to fail on variables which 217018e25fbSMichael Walsh contain blank values. 218018e25fbSMichael Walsh 219018e25fbSMichael Walsh It is illegal to specify both valid_values and invalid values. 220018e25fbSMichael Walsh 221018e25fbSMichael Walsh Example: 222018e25fbSMichael Walsh 223018e25fbSMichael Walsh var1 = '' 224018e25fbSMichael Walsh valid_value(var1) 225018e25fbSMichael Walsh 226018e25fbSMichael Walsh This code would fail because var1 is blank and the default value for 227018e25fbSMichael Walsh invalid_values is ['', None]. 228018e25fbSMichael Walsh 229018e25fbSMichael Walsh Example: 230018e25fbSMichael Walsh var1 = 'yes' 231018e25fbSMichael Walsh valid_value(var1, valid_values=['yes', 'true']) 232018e25fbSMichael Walsh 233018e25fbSMichael Walsh This code would pass. 234018e25fbSMichael Walsh 235018e25fbSMichael Walsh Description of argument(s): 236018e25fbSMichael Walsh var_value The value being validated. 237018e25fbSMichael Walsh valid_values A list of valid values. The variable 238018e25fbSMichael Walsh value must be equal to one of these values 239018e25fbSMichael Walsh to be considered valid. 240018e25fbSMichael Walsh invalid_values A list of invalid values. If the variable 241018e25fbSMichael Walsh value is equal to any of these, it is 242018e25fbSMichael Walsh considered invalid. 243018e25fbSMichael Walsh """ 244018e25fbSMichael Walsh 245bec416ddSMichael Walsh error_message = "" 246bec416ddSMichael Walsh 247e23b5ad3SMichael Walsh # Validate this function's arguments. 2487423c01aSMichael Walsh len_valid_values = len(valid_values) 2497423c01aSMichael Walsh len_invalid_values = len(invalid_values) 2507423c01aSMichael Walsh if len_valid_values > 0 and len_invalid_values > 0: 251018e25fbSMichael Walsh error_message += "Programmer error - You must provide either an" 252018e25fbSMichael Walsh error_message += " invalid_values list or a valid_values" 253018e25fbSMichael Walsh error_message += " list but NOT both:\n" 254018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values) 255018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values) 256018e25fbSMichael Walsh return process_error_message(error_message) 2577423c01aSMichael Walsh 2587423c01aSMichael Walsh if len_valid_values > 0: 2597423c01aSMichael Walsh # Processing the valid_values list. 2607423c01aSMichael Walsh if var_value in valid_values: 261018e25fbSMichael Walsh return process_error_message(error_message) 262018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 263018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 264018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 265018e25fbSMichael Walsh gp.blank() | gp.verbose() 266018e25fbSMichael Walsh | gp.show_type()) 267018e25fbSMichael Walsh error_message += "\n" 268018e25fbSMichael Walsh error_message += "It must be one of the following values:\n" 269018e25fbSMichael Walsh error_message += "\n" 270018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values, 271018e25fbSMichael Walsh gp.blank() | gp.show_type()) 272018e25fbSMichael Walsh return process_error_message(error_message) 2737423c01aSMichael Walsh 2747423c01aSMichael Walsh if len_invalid_values == 0: 275bec416ddSMichael Walsh # Assign default value. 276018e25fbSMichael Walsh invalid_values = ["", None] 2777423c01aSMichael Walsh 2787423c01aSMichael Walsh # Assertion: We have an invalid_values list. Processing it now. 2797423c01aSMichael Walsh if var_value not in invalid_values: 280018e25fbSMichael Walsh return process_error_message(error_message) 281bec416ddSMichael Walsh 282018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 283018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 284018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 285018e25fbSMichael Walsh gp.blank() | gp.verbose() 286018e25fbSMichael Walsh | gp.show_type()) 287018e25fbSMichael Walsh error_message += "\n" 288018e25fbSMichael Walsh error_message += "It must NOT be one of the following values:\n" 289018e25fbSMichael Walsh error_message += "\n" 290018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values, 291018e25fbSMichael Walsh gp.blank() | gp.show_type()) 292e23b5ad3SMichael Walsh return process_error_message(error_message) 2937423c01aSMichael Walsh 294bec416ddSMichael Walsh 295018e25fbSMichael Walshdef valid_range(var_value, lower=None, upper=None, *args, **kwargs): 296bec416ddSMichael Walsh r""" 297018e25fbSMichael Walsh The variable value is valid if it is within the specified range. 298bec416ddSMichael Walsh 299018e25fbSMichael Walsh This function can be used with any type of operands where they can have a 300018e25fbSMichael Walsh greater than/less than relationship to each other (e.g. int, float, str). 301018e25fbSMichael Walsh 302018e25fbSMichael Walsh Description of argument(s): 303bec416ddSMichael Walsh var_value The value being validated. 304018e25fbSMichael Walsh lower The lower end of the range. If not None, 305018e25fbSMichael Walsh the var_value must be greater than or 306018e25fbSMichael Walsh equal to lower. 307018e25fbSMichael Walsh upper The upper end of the range. If not None, 308018e25fbSMichael Walsh the var_value must be less than or equal 309018e25fbSMichael Walsh to upper. 310bec416ddSMichael Walsh """ 311bec416ddSMichael Walsh 312bec416ddSMichael Walsh error_message = "" 313*b9d8dfd2SMichael Walsh if lower is None and upper is None: 314018e25fbSMichael Walsh return process_error_message(error_message) 315*b9d8dfd2SMichael Walsh if lower is None and var_value <= upper: 316018e25fbSMichael Walsh return process_error_message(error_message) 317*b9d8dfd2SMichael Walsh if upper is None and var_value >= lower: 318018e25fbSMichael Walsh return process_error_message(error_message) 319018e25fbSMichael Walsh if lower and upper: 320018e25fbSMichael Walsh if lower > upper: 321018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 322018e25fbSMichael Walsh error_message += "Programmer error - the lower value is greater" 323018e25fbSMichael Walsh error_message += " than the upper value:\n" 324018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type()) 325018e25fbSMichael Walsh return process_error_message(error_message) 326018e25fbSMichael Walsh if lower <= var_value <= upper: 327018e25fbSMichael Walsh return process_error_message(error_message) 328bec416ddSMichael Walsh 329018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 330018e25fbSMichael Walsh error_message += "The following variable is not within the expected" 331018e25fbSMichael Walsh error_message += " range:\n" 332018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 333018e25fbSMichael Walsh error_message += "\n" 334018e25fbSMichael Walsh error_message += "range:\n" 335018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2) 336e23b5ad3SMichael Walsh return process_error_message(error_message) 3377423c01aSMichael Walsh 33878bdfdd6SMichael Walsh 339018e25fbSMichael Walshdef valid_integer(var_value, lower=None, upper=None, *args, **kwargs): 34078bdfdd6SMichael Walsh r""" 341018e25fbSMichael Walsh The variable value is valid if it is an integer or can be interpreted as 342018e25fbSMichael Walsh an integer (e.g. 7, "7", etc.). 34378bdfdd6SMichael Walsh 344018e25fbSMichael Walsh This function also calls valid_range to make sure the integer value is 345018e25fbSMichael Walsh within the specified range (if any). 346018e25fbSMichael Walsh 347018e25fbSMichael Walsh Description of argument(s): 34878bdfdd6SMichael Walsh var_value The value being validated. 349018e25fbSMichael Walsh lower The lower end of the range. If not None, 350018e25fbSMichael Walsh the var_value must be greater than or 351018e25fbSMichael Walsh equal to lower. 352018e25fbSMichael Walsh upper The upper end of the range. If not None, 353018e25fbSMichael Walsh the var_value must be less than or equal 354018e25fbSMichael Walsh to upper. 355018e25fbSMichael Walsh """ 356018e25fbSMichael Walsh 357018e25fbSMichael Walsh error_message = "" 358018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 359018e25fbSMichael Walsh try: 360018e25fbSMichael Walsh var_value = int(str(var_value), 0) 361018e25fbSMichael Walsh except ValueError: 362018e25fbSMichael Walsh error_message += "Invalid integer value:\n" 363018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 364018e25fbSMichael Walsh gp.blank() | gp.show_type()) 365018e25fbSMichael Walsh return process_error_message(error_message) 366018e25fbSMichael Walsh 367018e25fbSMichael Walsh # Check the range (if any). 368018e25fbSMichael Walsh if lower: 369018e25fbSMichael Walsh lower = int(str(lower), 0) 370018e25fbSMichael Walsh if upper: 371018e25fbSMichael Walsh upper = int(str(upper), 0) 372018e25fbSMichael Walsh error_message = valid_range(var_value, lower, upper, var_name=var_name) 373018e25fbSMichael Walsh 374018e25fbSMichael Walsh return process_error_message(error_message) 375018e25fbSMichael Walsh 376018e25fbSMichael Walsh 377018e25fbSMichael Walshdef valid_dir_path(var_value, *args, **kwargs): 378018e25fbSMichael Walsh r""" 379018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing 380018e25fbSMichael Walsh directory. 381018e25fbSMichael Walsh 382018e25fbSMichael Walsh Description of argument(s): 383018e25fbSMichael Walsh var_value The value being validated. 38478bdfdd6SMichael Walsh """ 38578bdfdd6SMichael Walsh 38678bdfdd6SMichael Walsh error_message = "" 38778bdfdd6SMichael Walsh if not os.path.isdir(str(var_value)): 388018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 389018e25fbSMichael Walsh error_message += "The following directory does not exist:\n" 39000244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 39178bdfdd6SMichael Walsh 392e23b5ad3SMichael Walsh return process_error_message(error_message) 39378bdfdd6SMichael Walsh 39478bdfdd6SMichael Walsh 395018e25fbSMichael Walshdef valid_file_path(var_value, *args, **kwargs): 39678bdfdd6SMichael Walsh r""" 397018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing file. 39878bdfdd6SMichael Walsh 399018e25fbSMichael Walsh Description of argument(s): 40078bdfdd6SMichael Walsh var_value The value being validated. 40178bdfdd6SMichael Walsh """ 40278bdfdd6SMichael Walsh 40378bdfdd6SMichael Walsh error_message = "" 40478bdfdd6SMichael Walsh if not os.path.isfile(str(var_value)): 405018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 406018e25fbSMichael Walsh error_message += "The following file does not exist:\n" 40700244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 40878bdfdd6SMichael Walsh 409e23b5ad3SMichael Walsh return process_error_message(error_message) 41078bdfdd6SMichael Walsh 41178bdfdd6SMichael Walsh 412018e25fbSMichael Walshdef valid_path(var_value, *args, **kwargs): 413e23b5ad3SMichael Walsh r""" 414018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing file or 415018e25fbSMichael Walsh directory. 416e23b5ad3SMichael Walsh 417018e25fbSMichael Walsh Description of argument(s): 418e23b5ad3SMichael Walsh var_value The value being validated. 419e23b5ad3SMichael Walsh """ 420e23b5ad3SMichael Walsh 421e23b5ad3SMichael Walsh error_message = "" 422e23b5ad3SMichael Walsh if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))): 423018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 424018e25fbSMichael Walsh error_message += "Invalid path (file or directory does not exist):\n" 42500244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 426e23b5ad3SMichael Walsh 427e23b5ad3SMichael Walsh return process_error_message(error_message) 4282c687e98SMichael Walsh 4292c687e98SMichael Walsh 43035026be5SMichael Walshdef valid_list(var_value, valid_values=[], invalid_values=[], 43135026be5SMichael Walsh required_values=[], fail_on_empty=False, *args, **kwargs): 4322c687e98SMichael Walsh r""" 433018e25fbSMichael Walsh The variable value is valid if it is a list where each entry can be found 43435026be5SMichael Walsh in the valid_values list or if none of its values can be found in the 43535026be5SMichael Walsh invalid_values list or if all of the values in the required_values list 43635026be5SMichael Walsh can be found in var_value. 43735026be5SMichael Walsh 43835026be5SMichael Walsh The caller may only specify one of these 3 arguments: valid_values, 43935026be5SMichael Walsh invalid_values, required_values. 4402c687e98SMichael Walsh 441018e25fbSMichael Walsh Description of argument(s): 442018e25fbSMichael Walsh var_value The value being validated. 443ca193993SMichael Walsh valid_values A list of valid values. Each element in 444ca193993SMichael Walsh the var_value list must be equal to one of 445ca193993SMichael Walsh these values to be considered valid. 44635026be5SMichael Walsh invalid_values A list of invalid values. If any element 44735026be5SMichael Walsh in var_value is equal to any of the values 44835026be5SMichael Walsh in this argument, var_value is considered 44935026be5SMichael Walsh invalid. 45035026be5SMichael Walsh required_values Every value in required_values must be 45135026be5SMichael Walsh found in var_value. Otherwise, var_value 45235026be5SMichael Walsh is considered invalid. 453018e25fbSMichael Walsh fail_on_empty Indicates that an empty list for the 454018e25fbSMichael Walsh variable value should be considered an 455018e25fbSMichael Walsh error. 456ca193993SMichael Walsh """ 457ca193993SMichael Walsh 458ca193993SMichael Walsh error_message = "" 459018e25fbSMichael Walsh 46035026be5SMichael Walsh # Validate this function's arguments. 46135026be5SMichael Walsh len_valid_values = len(valid_values) 46235026be5SMichael Walsh len_invalid_values = len(invalid_values) 46335026be5SMichael Walsh len_required_values = len(required_values) 46435026be5SMichael Walsh if (len_valid_values + len_invalid_values + len_required_values) > 1: 46535026be5SMichael Walsh error_message += "Programmer error - You must provide only one of the" 46635026be5SMichael Walsh error_message += " following: valid_values, invalid_values," 46735026be5SMichael Walsh error_message += " required_values.\n" 46835026be5SMichael Walsh error_message += gp.sprint_var(invalid_values) 46935026be5SMichael Walsh error_message += gp.sprint_var(valid_values) 47035026be5SMichael Walsh error_message += gp.sprint_var(required_values) 47135026be5SMichael Walsh return process_error_message(error_message) 47235026be5SMichael Walsh 473018e25fbSMichael Walsh if type(var_value) is not list: 474018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 475018e25fbSMichael Walsh error_message = valid_type(var_value, list, var_name=var_name) 476018e25fbSMichael Walsh if error_message: 477018e25fbSMichael Walsh return process_error_message(error_message) 478018e25fbSMichael Walsh 479018e25fbSMichael Walsh if fail_on_empty and len(var_value) == 0: 480018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 481018e25fbSMichael Walsh error_message += "Invalid empty list:\n" 482018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 483018e25fbSMichael Walsh return process_error_message(error_message) 484ca193993SMichael Walsh 48535026be5SMichael Walsh if len(required_values): 48635026be5SMichael Walsh found_error = 0 48735026be5SMichael Walsh display_required_values = list(required_values) 48835026be5SMichael Walsh for ix in range(0, len(required_values)): 48935026be5SMichael Walsh if required_values[ix] not in var_value: 49035026be5SMichael Walsh found_error = 1 49135026be5SMichael Walsh display_required_values[ix] = \ 49235026be5SMichael Walsh str(display_required_values[ix]) + "*" 49335026be5SMichael Walsh if found_error: 49435026be5SMichael Walsh var_name = get_var_name(*args, **kwargs) 49535026be5SMichael Walsh error_message += "The following list is invalid:\n" 49635026be5SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 49735026be5SMichael Walsh gp.blank() | gp.show_type()) 49835026be5SMichael Walsh error_message += "\n" 49935026be5SMichael Walsh error_message += "Because some of the values in the " 50035026be5SMichael Walsh error_message += "required_values list are not present (see" 50135026be5SMichael Walsh error_message += " entries marked with \"*\"):\n" 50235026be5SMichael Walsh error_message += "\n" 50335026be5SMichael Walsh error_message += gp.sprint_varx('required_values', 50435026be5SMichael Walsh display_required_values, 50535026be5SMichael Walsh gp.blank() | gp.show_type()) 50635026be5SMichael Walsh error_message += "\n" 50735026be5SMichael Walsh 50835026be5SMichael Walsh return process_error_message(error_message) 50935026be5SMichael Walsh 51035026be5SMichael Walsh if len(invalid_values): 51135026be5SMichael Walsh found_error = 0 51235026be5SMichael Walsh display_var_value = list(var_value) 51335026be5SMichael Walsh for ix in range(0, len(var_value)): 51435026be5SMichael Walsh if var_value[ix] in invalid_values: 51535026be5SMichael Walsh found_error = 1 51635026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 51735026be5SMichael Walsh 51835026be5SMichael Walsh if found_error: 51935026be5SMichael Walsh var_name = get_var_name(*args, **kwargs) 52035026be5SMichael Walsh error_message += "The following list is invalid (see entries" 52135026be5SMichael Walsh error_message += " marked with \"*\"):\n" 52235026be5SMichael Walsh error_message += gp.sprint_varx(var_name, display_var_value, 52335026be5SMichael Walsh gp.blank() | gp.show_type()) 52435026be5SMichael Walsh error_message += "\n" 52535026be5SMichael Walsh error_message += gp.sprint_var(invalid_values, gp.show_type()) 52635026be5SMichael Walsh return process_error_message(error_message) 52735026be5SMichael Walsh 528ca193993SMichael Walsh found_error = 0 529ca193993SMichael Walsh display_var_value = list(var_value) 530ca193993SMichael Walsh for ix in range(0, len(var_value)): 531ca193993SMichael Walsh if var_value[ix] not in valid_values: 532ca193993SMichael Walsh found_error = 1 53335026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 534ca193993SMichael Walsh 535ca193993SMichael Walsh if found_error: 536018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 537018e25fbSMichael Walsh error_message += "The following list is invalid (see entries marked" 538018e25fbSMichael Walsh error_message += " with \"*\"):\n" 539018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, display_var_value, 540018e25fbSMichael Walsh gp.blank() | gp.show_type()) 541018e25fbSMichael Walsh error_message += "\n" 54235026be5SMichael Walsh error_message += gp.sprint_var(valid_values, gp.show_type()) 543018e25fbSMichael Walsh return process_error_message(error_message) 544ca193993SMichael Walsh 545ca193993SMichael Walsh return process_error_message(error_message) 5467ac5fd81SMichael Walsh 5477ac5fd81SMichael Walsh 548018e25fbSMichael Walshdef valid_dict(var_value, required_keys=[], *args, **kwargs): 5497ac5fd81SMichael Walsh r""" 550018e25fbSMichael Walsh The variable value is valid if it is a dictionary containing all of the 551018e25fbSMichael Walsh required keys. 5527ac5fd81SMichael Walsh 553018e25fbSMichael Walsh Description of argument(s): 554018e25fbSMichael Walsh var_value The value being validated. 5557ac5fd81SMichael Walsh required_keys A list of keys which must be found in the 5567ac5fd81SMichael Walsh dictionary for it to be considered valid. 5577ac5fd81SMichael Walsh """ 5587ac5fd81SMichael Walsh 5597ac5fd81SMichael Walsh error_message = "" 560018e25fbSMichael Walsh missing_keys = list(set(required_keys) - set(var_value.keys())) 561018e25fbSMichael Walsh if len(missing_keys) > 0: 562018e25fbSMichael Walsh var_name = get_var_name(*args, **kwargs) 563018e25fbSMichael Walsh error_message += "The following dictionary is invalid because it is" 564018e25fbSMichael Walsh error_message += " missing required keys:\n" 565018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 566018e25fbSMichael Walsh gp.blank() | gp.show_type()) 567018e25fbSMichael Walsh error_message += "\n" 56835026be5SMichael Walsh error_message += gp.sprint_var(missing_keys, gp.show_type()) 5697ac5fd81SMichael Walsh return process_error_message(error_message) 570018e25fbSMichael Walsh 571018e25fbSMichael Walsh 572be3a8150SMichael Walshdef valid_program(var_value, *args, **kwargs): 573be3a8150SMichael Walsh r""" 574be3a8150SMichael Walsh The variable value is valid if it contains the name of a program which can 575be3a8150SMichael Walsh be located using the "which" command. 576be3a8150SMichael Walsh 577be3a8150SMichael Walsh Description of argument(s): 578be3a8150SMichael Walsh var_value The value being validated. 579be3a8150SMichael Walsh """ 580be3a8150SMichael Walsh 581be3a8150SMichael Walsh error_message = "" 582be3a8150SMichael Walsh rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0, 583be3a8150SMichael Walsh ignore_err=1) 584be3a8150SMichael Walsh if rc: 585be3a8150SMichael Walsh var_name = get_var_name(*args, **kwargs) 586be3a8150SMichael Walsh error_message += "The following required program could not be found" 587be3a8150SMichael Walsh error_message += " using the $PATH environment variable:\n" 58800244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 589be3a8150SMichael Walsh PATH = os.environ.get("PATH", "").split(":") 590be3a8150SMichael Walsh error_message += "\n" 591be3a8150SMichael Walsh error_message += gp.sprint_var(PATH) 592be3a8150SMichael Walsh return process_error_message(error_message) 593be3a8150SMichael Walsh 594be3a8150SMichael Walsh 595*b9d8dfd2SMichael Walshdef valid_length(var_value, min_length=None, max_length=None, *args, **kwargs): 596*b9d8dfd2SMichael Walsh r""" 597*b9d8dfd2SMichael Walsh The variable value is valid if it is an object (e.g. list, dictionary) 598*b9d8dfd2SMichael Walsh whose length is within the specified range. 599*b9d8dfd2SMichael Walsh 600*b9d8dfd2SMichael Walsh Description of argument(s): 601*b9d8dfd2SMichael Walsh var_value The value being validated. 602*b9d8dfd2SMichael Walsh min_length The minimum length of the object. If not 603*b9d8dfd2SMichael Walsh None, the length of var_value must be 604*b9d8dfd2SMichael Walsh greater than or equal to min_length. 605*b9d8dfd2SMichael Walsh max_length The maximum length of the object. If not 606*b9d8dfd2SMichael Walsh None, the length of var_value must be less 607*b9d8dfd2SMichael Walsh than or equal to min_length. 608*b9d8dfd2SMichael Walsh """ 609*b9d8dfd2SMichael Walsh 610*b9d8dfd2SMichael Walsh error_message = "" 611*b9d8dfd2SMichael Walsh length = len(var_value) 612*b9d8dfd2SMichael Walsh error_message = valid_range(length, min_length, max_length) 613*b9d8dfd2SMichael Walsh if error_message: 614*b9d8dfd2SMichael Walsh var_name = get_var_name(*args, **kwargs) 615*b9d8dfd2SMichael Walsh error_message = "The length of the following object is not within the" 616*b9d8dfd2SMichael Walsh error_message += " expected range:\n" 617*b9d8dfd2SMichael Walsh error_message += gp.sprint_var(length) 618*b9d8dfd2SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 619*b9d8dfd2SMichael Walsh error_message += "\n" 620*b9d8dfd2SMichael Walsh error_message += gp.sprint_vars(min_length, max_length) 621*b9d8dfd2SMichael Walsh return process_error_message(error_message) 622*b9d8dfd2SMichael Walsh 623*b9d8dfd2SMichael Walsh return process_error_message(error_message) 624*b9d8dfd2SMichael Walsh 625*b9d8dfd2SMichael Walsh 626018e25fbSMichael Walsh# Modify selected function docstrings by adding headers/footers. 627018e25fbSMichael Walsh 628018e25fbSMichael Walshfunc_names = [ 629018e25fbSMichael Walsh "valid_type", "valid_value", "valid_range", "valid_integer", 630018e25fbSMichael Walsh "valid_dir_path", "valid_file_path", "valid_path", "valid_list", 631be3a8150SMichael Walsh "valid_dict", "valid_program" 632018e25fbSMichael Walsh] 633018e25fbSMichael Walsh 634018e25fbSMichael Walshraw_doc_strings = {} 635018e25fbSMichael Walsh 636018e25fbSMichael Walshfor func_name in func_names: 637018e25fbSMichael Walsh cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name 638018e25fbSMichael Walsh cmd_buf += ".__doc__" 639018e25fbSMichael Walsh exec(cmd_buf) 640018e25fbSMichael Walsh cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name 641018e25fbSMichael Walsh cmd_buf += ".__doc__.rstrip(\" \\n\") + additional_args_docstring_footer" 642018e25fbSMichael Walsh exec(cmd_buf) 643