1e7e9171eSGeorge Keishing#!/usr/bin/env python3 27423c01aSMichael Walsh 37423c01aSMichael Walshr""" 4da20f845SMichael WalshThis module provides validation functions like valid_value(), valid_integer(), etc. 57423c01aSMichael Walsh""" 67423c01aSMichael Walsh 7e635ddc0SGeorge Keishingimport datetime 8*20f38712SPatrick Williamsimport os 9*20f38712SPatrick Williams 10*20f38712SPatrick Williamsimport func_args as fa 11*20f38712SPatrick Williamsimport gen_cmd as gc 12*20f38712SPatrick Williamsimport gen_print as gp 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 21da20f845SMichael Walsh If exit_on_error is set, validation functions like valid_value() will exit the program on error instead 22da20f845SMichael Walsh 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 3289eff544SMichael Walshdef get_var_name(var_name): 33e23b5ad3SMichael Walsh r""" 34da20f845SMichael Walsh If var_name is not None, simply return its value. Otherwise, get the variable name of the first argument 35da20f845SMichael Walsh used to call the validation 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 6789eff544SMichael Walsh return var_name or gp.get_arg_name(0, 1, stack_frame_ix=3) 68e23b5ad3SMichael Walsh 69e23b5ad3SMichael Walsh 70e23b5ad3SMichael Walshdef process_error_message(error_message): 71e23b5ad3SMichael Walsh r""" 72018e25fbSMichael Walsh Process the error_message in the manner described below. 73e23b5ad3SMichael Walsh 74018e25fbSMichael Walsh This function is designed solely for use by other functions in this file. 75018e25fbSMichael Walsh 76018e25fbSMichael Walsh NOTE: A blank error_message means that there is no error. 77018e25fbSMichael Walsh 78da20f845SMichael Walsh For the following explanations, assume the caller of this function is a function with the following 79da20f845SMichael Walsh definition: 8089eff544SMichael Walsh valid_value(var_value, valid_values=[], invalid_values=[], var_name=None): 81018e25fbSMichael Walsh 82da20f845SMichael Walsh If the user of valid_value() is assigning the valid_value() return value to a variable, 83da20f845SMichael Walsh process_error_message() will simply return the error_message. This mode of usage is illustrated by the 84da20f845SMichael Walsh following example: 85018e25fbSMichael Walsh 86018e25fbSMichael Walsh error_message = valid_value(var1) 87018e25fbSMichael Walsh 88da20f845SMichael Walsh This mode is useful for callers who wish to validate a variable and then decide for themselves what to do 89da20f845SMichael Walsh with the error_message (e.g. raise(error_message), BuiltIn().fail(error_message), etc.). 90018e25fbSMichael Walsh 91da20f845SMichael Walsh If the user of valid_value() is NOT assigning the valid_value() return value to a variable, 92da20f845SMichael Walsh process_error_message() will behave as follows. 93018e25fbSMichael Walsh 94da20f845SMichael Walsh First, if error_message is non-blank, it will be printed to stderr via a call to 95da20f845SMichael Walsh gp.print_error_report(error_message). 96018e25fbSMichael Walsh 97018e25fbSMichael Walsh If exit_on_error is set: 98018e25fbSMichael Walsh - If the error_message is blank, simply return. 99da20f845SMichael Walsh - If the error_message is non-blank, exit the program with a return code of 1. 100018e25fbSMichael Walsh 101018e25fbSMichael Walsh If exit_on_error is NOT set: 102018e25fbSMichael Walsh - If the error_message is blank, return True. 103018e25fbSMichael Walsh - If the error_message is non-blank, return False. 104e23b5ad3SMichael Walsh 105e23b5ad3SMichael Walsh Description of argument(s): 106e23b5ad3SMichael Walsh error_message An error message. 107e23b5ad3SMichael Walsh """ 108e23b5ad3SMichael Walsh 109da20f845SMichael Walsh # Determine whether the caller's caller is assigning the result to a variable. 110018e25fbSMichael Walsh l_value = gp.get_arg_name(None, -1, stack_frame_ix=3) 111018e25fbSMichael Walsh if l_value: 112018e25fbSMichael Walsh return error_message 113018e25fbSMichael Walsh 114e23b5ad3SMichael Walsh if error_message == "": 115018e25fbSMichael Walsh if exit_on_error: 116018e25fbSMichael Walsh return 117e23b5ad3SMichael Walsh return True 118e23b5ad3SMichael Walsh 119018e25fbSMichael Walsh gp.print_error_report(error_message, stack_frame_ix=4) 120e23b5ad3SMichael Walsh if exit_on_error: 12110a4d98bSMichael Walsh exit(1) 122e23b5ad3SMichael Walsh return False 123e23b5ad3SMichael Walsh 1247423c01aSMichael Walsh 125da20f845SMichael Walsh# Note to programmers: All of the validation functions in this module should follow the same basic template: 12689eff544SMichael Walsh# def valid_value(var_value, var1, var2, varn, var_name=None): 127018e25fbSMichael Walsh# 128018e25fbSMichael Walsh# error_message = "" 129018e25fbSMichael Walsh# if not valid: 13089eff544SMichael Walsh# var_name = get_var_name(var_name) 131018e25fbSMichael Walsh# error_message += "The following variable is invalid because...:\n" 132018e25fbSMichael Walsh# error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 133018e25fbSMichael Walsh# 134018e25fbSMichael Walsh# return process_error_message(error_message) 1357423c01aSMichael Walsh 136018e25fbSMichael Walsh 137da20f845SMichael Walsh# The docstring header and footer will be added to each validation function's existing docstring. 138*20f38712SPatrick Williamsdocstring_header = r""" 139018e25fbSMichael Walsh Determine whether var_value is valid, construct an error_message and call 140018e25fbSMichael Walsh process_error_message(error_message). 141018e25fbSMichael Walsh 142da20f845SMichael Walsh See the process_error_message() function defined in this module for a description of how error messages 143da20f845SMichael Walsh are processed. 1447423c01aSMichael Walsh """ 1457423c01aSMichael Walsh 146*20f38712SPatrick Williamsadditional_args_docstring_footer = r""" 147da20f845SMichael Walsh var_name The name of the variable whose value is passed in var_value. For the 148da20f845SMichael Walsh general case, this argument is unnecessary as this function can figure 149da20f845SMichael Walsh out the var_name. This is provided for Robot callers in which case, this 150da20f845SMichael Walsh function lacks the ability to determine the variable name. 151018e25fbSMichael Walsh """ 152018e25fbSMichael Walsh 153018e25fbSMichael Walsh 15489eff544SMichael Walshdef valid_type(var_value, required_type, var_name=None): 155018e25fbSMichael Walsh r""" 156018e25fbSMichael Walsh The variable value is valid if it is of the required type. 157018e25fbSMichael Walsh 158018e25fbSMichael Walsh Examples: 159018e25fbSMichael Walsh 160018e25fbSMichael Walsh valid_type(var1, int) 161018e25fbSMichael Walsh 162018e25fbSMichael Walsh valid_type(var1, (list, dict)) 163018e25fbSMichael Walsh 164018e25fbSMichael Walsh Description of argument(s): 165018e25fbSMichael Walsh var_value The value being validated. 166da20f845SMichael Walsh required_type A type or a tuple of types (e.g. str, int, etc.). 167018e25fbSMichael Walsh """ 168018e25fbSMichael Walsh 169018e25fbSMichael Walsh error_message = "" 170018e25fbSMichael Walsh if type(required_type) is tuple: 171018e25fbSMichael Walsh if type(var_value) in required_type: 172018e25fbSMichael Walsh return process_error_message(error_message) 173018e25fbSMichael Walsh else: 174018e25fbSMichael Walsh if type(var_value) is required_type: 175018e25fbSMichael Walsh return process_error_message(error_message) 176018e25fbSMichael Walsh 177018e25fbSMichael Walsh # If we get to this point, the validation has failed. 17889eff544SMichael Walsh var_name = get_var_name(var_name) 179018e25fbSMichael Walsh error_message += "Invalid variable type:\n" 180*20f38712SPatrick Williams error_message += gp.sprint_varx( 181*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 182*20f38712SPatrick Williams ) 183018e25fbSMichael Walsh error_message += "\n" 184018e25fbSMichael Walsh error_message += gp.sprint_var(required_type) 185018e25fbSMichael Walsh 186018e25fbSMichael Walsh return process_error_message(error_message) 187018e25fbSMichael Walsh 188018e25fbSMichael Walsh 18989eff544SMichael Walshdef valid_value(var_value, valid_values=[], invalid_values=[], var_name=None): 190018e25fbSMichael Walsh r""" 191da20f845SMichael Walsh The variable value is valid if it is either contained in the valid_values list or if it is NOT contained 192da20f845SMichael Walsh in the invalid_values list. If the caller specifies nothing for either of these 2 arguments, 193da20f845SMichael Walsh invalid_values will be initialized to ['', None]. This is a good way to fail on variables which contain 194da20f845SMichael Walsh blank values. 195018e25fbSMichael Walsh 196018e25fbSMichael Walsh It is illegal to specify both valid_values and invalid values. 197018e25fbSMichael Walsh 198018e25fbSMichael Walsh Example: 199018e25fbSMichael Walsh 200018e25fbSMichael Walsh var1 = '' 201018e25fbSMichael Walsh valid_value(var1) 202018e25fbSMichael Walsh 203da20f845SMichael Walsh This code would fail because var1 is blank and the default value for invalid_values is ['', None]. 204018e25fbSMichael Walsh 205018e25fbSMichael Walsh Example: 206018e25fbSMichael Walsh var1 = 'yes' 207018e25fbSMichael Walsh valid_value(var1, valid_values=['yes', 'true']) 208018e25fbSMichael Walsh 209018e25fbSMichael Walsh This code would pass. 210018e25fbSMichael Walsh 211018e25fbSMichael Walsh Description of argument(s): 212018e25fbSMichael Walsh var_value The value being validated. 213da20f845SMichael Walsh valid_values A list of valid values. The variable value must be equal to one of these 214da20f845SMichael Walsh values to be considered valid. 215da20f845SMichael Walsh invalid_values A list of invalid values. If the variable value is equal to any of 216da20f845SMichael Walsh these, it is considered invalid. 217018e25fbSMichael Walsh """ 218018e25fbSMichael Walsh 219bec416ddSMichael Walsh error_message = "" 220bec416ddSMichael Walsh 221e23b5ad3SMichael Walsh # Validate this function's arguments. 2227423c01aSMichael Walsh len_valid_values = len(valid_values) 2237423c01aSMichael Walsh len_invalid_values = len(invalid_values) 2247423c01aSMichael Walsh if len_valid_values > 0 and len_invalid_values > 0: 225018e25fbSMichael Walsh error_message += "Programmer error - You must provide either an" 226018e25fbSMichael Walsh error_message += " invalid_values list or a valid_values" 227018e25fbSMichael Walsh error_message += " list but NOT both:\n" 228018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values) 229018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values) 230018e25fbSMichael Walsh return process_error_message(error_message) 2317423c01aSMichael Walsh 232*20f38712SPatrick Williams error_message = valid_type(valid_values, list, var_name="valid_values") 2330f5fa532SMichael Walsh if error_message: 2340f5fa532SMichael Walsh return process_error_message(error_message) 2350f5fa532SMichael Walsh 236*20f38712SPatrick Williams error_message = valid_type(invalid_values, list, var_name="invalid_values") 2370f5fa532SMichael Walsh if error_message: 2380f5fa532SMichael Walsh return process_error_message(error_message) 2390f5fa532SMichael Walsh 2407423c01aSMichael Walsh if len_valid_values > 0: 2417423c01aSMichael Walsh # Processing the valid_values list. 2427423c01aSMichael Walsh if var_value in valid_values: 243018e25fbSMichael Walsh return process_error_message(error_message) 24489eff544SMichael Walsh var_name = get_var_name(var_name) 245018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 246*20f38712SPatrick Williams error_message += gp.sprint_varx( 247*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.verbose() | gp.show_type() 248*20f38712SPatrick Williams ) 249018e25fbSMichael Walsh error_message += "\n" 250018e25fbSMichael Walsh error_message += "It must be one of the following values:\n" 251018e25fbSMichael Walsh error_message += "\n" 252*20f38712SPatrick Williams error_message += gp.sprint_var( 253*20f38712SPatrick Williams valid_values, gp.blank() | gp.show_type() 254*20f38712SPatrick Williams ) 255018e25fbSMichael Walsh return process_error_message(error_message) 2567423c01aSMichael Walsh 2577423c01aSMichael Walsh if len_invalid_values == 0: 258bec416ddSMichael Walsh # Assign default value. 259018e25fbSMichael Walsh invalid_values = ["", None] 2607423c01aSMichael Walsh 2617423c01aSMichael Walsh # Assertion: We have an invalid_values list. Processing it now. 2627423c01aSMichael Walsh if var_value not in invalid_values: 263018e25fbSMichael Walsh return process_error_message(error_message) 264bec416ddSMichael Walsh 26589eff544SMichael Walsh var_name = get_var_name(var_name) 266018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 267*20f38712SPatrick Williams error_message += gp.sprint_varx( 268*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.verbose() | gp.show_type() 269*20f38712SPatrick Williams ) 270018e25fbSMichael Walsh error_message += "\n" 27153902dd1SMichael Walsh error_message += "It must NOT be any of the following values:\n" 272018e25fbSMichael Walsh error_message += "\n" 273*20f38712SPatrick Williams error_message += gp.sprint_var(invalid_values, gp.blank() | gp.show_type()) 274e23b5ad3SMichael Walsh return process_error_message(error_message) 2757423c01aSMichael Walsh 276bec416ddSMichael Walsh 27789eff544SMichael Walshdef valid_range(var_value, lower=None, upper=None, var_name=None): 278bec416ddSMichael Walsh r""" 279018e25fbSMichael Walsh The variable value is valid if it is within the specified range. 280bec416ddSMichael Walsh 281da20f845SMichael Walsh This function can be used with any type of operands where they can have a greater than/less than 282da20f845SMichael Walsh relationship to each other (e.g. int, float, str). 283018e25fbSMichael Walsh 284018e25fbSMichael Walsh Description of argument(s): 285bec416ddSMichael Walsh var_value The value being validated. 286da20f845SMichael Walsh lower The lower end of the range. If not None, the var_value must be greater 287da20f845SMichael Walsh than or equal to lower. 288da20f845SMichael Walsh upper The upper end of the range. If not None, the var_value must be less than 289da20f845SMichael Walsh or equal to upper. 290bec416ddSMichael Walsh """ 291bec416ddSMichael Walsh 292bec416ddSMichael Walsh error_message = "" 293b9d8dfd2SMichael Walsh if lower is None and upper is None: 294018e25fbSMichael Walsh return process_error_message(error_message) 295b9d8dfd2SMichael Walsh if lower is None and var_value <= upper: 296018e25fbSMichael Walsh return process_error_message(error_message) 297b9d8dfd2SMichael Walsh if upper is None and var_value >= lower: 298018e25fbSMichael Walsh return process_error_message(error_message) 2992f88a81fSTony Lee if lower is not None and upper is not None: 300018e25fbSMichael Walsh if lower > upper: 30189eff544SMichael Walsh var_name = get_var_name(var_name) 302018e25fbSMichael Walsh error_message += "Programmer error - the lower value is greater" 303018e25fbSMichael Walsh error_message += " than the upper value:\n" 304018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type()) 305018e25fbSMichael Walsh return process_error_message(error_message) 306018e25fbSMichael Walsh if lower <= var_value <= upper: 307018e25fbSMichael Walsh return process_error_message(error_message) 308bec416ddSMichael Walsh 30989eff544SMichael Walsh var_name = get_var_name(var_name) 310018e25fbSMichael Walsh error_message += "The following variable is not within the expected" 311018e25fbSMichael Walsh error_message += " range:\n" 312018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 313018e25fbSMichael Walsh error_message += "\n" 314018e25fbSMichael Walsh error_message += "range:\n" 315018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2) 316e23b5ad3SMichael Walsh return process_error_message(error_message) 3177423c01aSMichael Walsh 31878bdfdd6SMichael Walsh 31989eff544SMichael Walshdef valid_integer(var_value, lower=None, upper=None, var_name=None): 32078bdfdd6SMichael Walsh r""" 321da20f845SMichael Walsh The variable value is valid if it is an integer or can be interpreted as an integer (e.g. 7, "7", etc.). 32278bdfdd6SMichael Walsh 323da20f845SMichael Walsh This function also calls valid_range to make sure the integer value is within the specified range (if 324da20f845SMichael Walsh any). 325018e25fbSMichael Walsh 326018e25fbSMichael Walsh Description of argument(s): 32778bdfdd6SMichael Walsh var_value The value being validated. 328da20f845SMichael Walsh lower The lower end of the range. If not None, the var_value must be greater 329da20f845SMichael Walsh than or equal to lower. 330da20f845SMichael Walsh upper The upper end of the range. If not None, the var_value must be less than 331da20f845SMichael Walsh or equal to upper. 332018e25fbSMichael Walsh """ 333018e25fbSMichael Walsh 334018e25fbSMichael Walsh error_message = "" 33589eff544SMichael Walsh var_name = get_var_name(var_name) 336018e25fbSMichael Walsh try: 337018e25fbSMichael Walsh var_value = int(str(var_value), 0) 338018e25fbSMichael Walsh except ValueError: 339018e25fbSMichael Walsh error_message += "Invalid integer value:\n" 340*20f38712SPatrick Williams error_message += gp.sprint_varx( 341*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 342*20f38712SPatrick Williams ) 343018e25fbSMichael Walsh return process_error_message(error_message) 344018e25fbSMichael Walsh 345018e25fbSMichael Walsh # Check the range (if any). 346018e25fbSMichael Walsh if lower: 347018e25fbSMichael Walsh lower = int(str(lower), 0) 348018e25fbSMichael Walsh if upper: 349018e25fbSMichael Walsh upper = int(str(upper), 0) 350018e25fbSMichael Walsh error_message = valid_range(var_value, lower, upper, var_name=var_name) 351018e25fbSMichael Walsh 352018e25fbSMichael Walsh return process_error_message(error_message) 353018e25fbSMichael Walsh 354018e25fbSMichael Walsh 3558333a18dSMichael Walshdef valid_float(var_value, lower=None, upper=None, var_name=None): 3568333a18dSMichael Walsh r""" 3578333a18dSMichael Walsh The variable value is valid if it is a floating point value or can be interpreted as a floating point 3588333a18dSMichael Walsh value (e.g. 7.5, "7.5", etc.). 3598333a18dSMichael Walsh 3608333a18dSMichael Walsh This function also calls valid_range to make sure the float value is within the specified range (if any). 3618333a18dSMichael Walsh 3628333a18dSMichael Walsh Description of argument(s): 3638333a18dSMichael Walsh var_value The value being validated. 3648333a18dSMichael Walsh lower The lower end of the range. If not None, the var_value must be greater 3658333a18dSMichael Walsh than or equal to lower. 3668333a18dSMichael Walsh upper The upper end of the range. If not None, the var_value must be less than 3678333a18dSMichael Walsh or equal to upper. 3688333a18dSMichael Walsh """ 3698333a18dSMichael Walsh 3708333a18dSMichael Walsh error_message = "" 3718333a18dSMichael Walsh var_name = get_var_name(var_name) 3728333a18dSMichael Walsh try: 3738333a18dSMichael Walsh var_value = float(str(var_value)) 3748333a18dSMichael Walsh except ValueError: 3758333a18dSMichael Walsh error_message += "Invalid float value:\n" 376*20f38712SPatrick Williams error_message += gp.sprint_varx( 377*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 378*20f38712SPatrick Williams ) 3798333a18dSMichael Walsh return process_error_message(error_message) 3808333a18dSMichael Walsh 3818333a18dSMichael Walsh # Check the range (if any). 3828333a18dSMichael Walsh if lower: 3838333a18dSMichael Walsh lower = float(str(lower)) 3848333a18dSMichael Walsh if upper: 3858333a18dSMichael Walsh upper = float(str(upper)) 3868333a18dSMichael Walsh error_message = valid_range(var_value, lower, upper, var_name=var_name) 3878333a18dSMichael Walsh 3888333a18dSMichael Walsh return process_error_message(error_message) 3898333a18dSMichael Walsh 3908333a18dSMichael Walsh 3918333a18dSMichael Walshdef valid_date_time(var_value, var_name=None): 3928333a18dSMichael Walsh r""" 3938333a18dSMichael Walsh The variable value is valid if it can be interpreted as a date/time (e.g. "14:49:49.981", "tomorrow", 3948333a18dSMichael Walsh etc.) by the linux date command. 3958333a18dSMichael Walsh 3968333a18dSMichael Walsh Description of argument(s): 3978333a18dSMichael Walsh var_value The value being validated. 3988333a18dSMichael Walsh """ 3998333a18dSMichael Walsh 4008333a18dSMichael Walsh error_message = "" 401*20f38712SPatrick Williams rc, out_buf = gc.shell_cmd( 402*20f38712SPatrick Williams "date -d '" + str(var_value) + "'", quiet=1, show_err=0, ignore_err=1 403*20f38712SPatrick Williams ) 4048333a18dSMichael Walsh if rc: 4058333a18dSMichael Walsh var_name = get_var_name(var_name) 4068333a18dSMichael Walsh error_message += "Invalid date/time value:\n" 407*20f38712SPatrick Williams error_message += gp.sprint_varx( 408*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 409*20f38712SPatrick Williams ) 4108333a18dSMichael Walsh return process_error_message(error_message) 4118333a18dSMichael Walsh 4128333a18dSMichael Walsh return process_error_message(error_message) 4138333a18dSMichael Walsh 4148333a18dSMichael Walsh 41589eff544SMichael Walshdef valid_dir_path(var_value, var_name=None): 416018e25fbSMichael Walsh r""" 417da20f845SMichael Walsh The variable value is valid if it contains the path of an existing directory. 418018e25fbSMichael Walsh 419018e25fbSMichael Walsh Description of argument(s): 420018e25fbSMichael Walsh var_value The value being validated. 42178bdfdd6SMichael Walsh """ 42278bdfdd6SMichael Walsh 42378bdfdd6SMichael Walsh error_message = "" 42478bdfdd6SMichael Walsh if not os.path.isdir(str(var_value)): 42589eff544SMichael Walsh var_name = get_var_name(var_name) 426018e25fbSMichael Walsh error_message += "The following directory does not exist:\n" 42700244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 42878bdfdd6SMichael Walsh 429e23b5ad3SMichael Walsh return process_error_message(error_message) 43078bdfdd6SMichael Walsh 43178bdfdd6SMichael Walsh 43289eff544SMichael Walshdef valid_file_path(var_value, var_name=None): 43378bdfdd6SMichael Walsh r""" 434018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing file. 43578bdfdd6SMichael Walsh 436018e25fbSMichael Walsh Description of argument(s): 43778bdfdd6SMichael Walsh var_value The value being validated. 43878bdfdd6SMichael Walsh """ 43978bdfdd6SMichael Walsh 44078bdfdd6SMichael Walsh error_message = "" 44178bdfdd6SMichael Walsh if not os.path.isfile(str(var_value)): 44289eff544SMichael Walsh var_name = get_var_name(var_name) 443018e25fbSMichael Walsh error_message += "The following file does not exist:\n" 44400244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 44578bdfdd6SMichael Walsh 446e23b5ad3SMichael Walsh return process_error_message(error_message) 44778bdfdd6SMichael Walsh 44878bdfdd6SMichael Walsh 44989eff544SMichael Walshdef valid_path(var_value, var_name=None): 450e23b5ad3SMichael Walsh r""" 451da20f845SMichael Walsh The variable value is valid if it contains the path of an existing file or directory. 452e23b5ad3SMichael Walsh 453018e25fbSMichael Walsh Description of argument(s): 454e23b5ad3SMichael Walsh var_value The value being validated. 455e23b5ad3SMichael Walsh """ 456e23b5ad3SMichael Walsh 457e23b5ad3SMichael Walsh error_message = "" 458e23b5ad3SMichael Walsh if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))): 45989eff544SMichael Walsh var_name = get_var_name(var_name) 460018e25fbSMichael Walsh error_message += "Invalid path (file or directory does not exist):\n" 46100244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 462e23b5ad3SMichael Walsh 463e23b5ad3SMichael Walsh return process_error_message(error_message) 4642c687e98SMichael Walsh 4652c687e98SMichael Walsh 466*20f38712SPatrick Williamsdef valid_list( 467*20f38712SPatrick Williams var_value, 468*20f38712SPatrick Williams valid_values=[], 469*20f38712SPatrick Williams invalid_values=[], 470*20f38712SPatrick Williams required_values=[], 471*20f38712SPatrick Williams fail_on_empty=False, 472*20f38712SPatrick Williams var_name=None, 473*20f38712SPatrick Williams): 4742c687e98SMichael Walsh r""" 475da20f845SMichael Walsh The variable value is valid if it is a list where each entry can be found in the valid_values list or if 476da20f845SMichael Walsh none of its values can be found in the invalid_values list or if all of the values in the required_values 477da20f845SMichael Walsh list can be found in var_value. 47835026be5SMichael Walsh 479da20f845SMichael Walsh The caller may only specify one of these 3 arguments: valid_values, invalid_values, required_values. 4802c687e98SMichael Walsh 481018e25fbSMichael Walsh Description of argument(s): 482018e25fbSMichael Walsh var_value The value being validated. 483da20f845SMichael Walsh valid_values A list of valid values. Each element in the var_value list must be equal 484da20f845SMichael Walsh to one of these values to be considered valid. 485da20f845SMichael Walsh invalid_values A list of invalid values. If any element in var_value is equal to any of 486da20f845SMichael Walsh the values in this argument, var_value is considered invalid. 487da20f845SMichael Walsh required_values Every value in required_values must be found in var_value. Otherwise, 488da20f845SMichael Walsh var_value is considered invalid. 489da20f845SMichael Walsh fail_on_empty Indicates that an empty list for the variable value should be considered 490da20f845SMichael Walsh an error. 491ca193993SMichael Walsh """ 492ca193993SMichael Walsh 493ca193993SMichael Walsh error_message = "" 494018e25fbSMichael Walsh 49535026be5SMichael Walsh # Validate this function's arguments. 496*20f38712SPatrick Williams if not ( 497*20f38712SPatrick Williams bool(len(valid_values)) 498*20f38712SPatrick Williams ^ bool(len(invalid_values)) 499*20f38712SPatrick Williams ^ bool(len(required_values)) 500*20f38712SPatrick Williams ): 50135026be5SMichael Walsh error_message += "Programmer error - You must provide only one of the" 50235026be5SMichael Walsh error_message += " following: valid_values, invalid_values," 50335026be5SMichael Walsh error_message += " required_values.\n" 504da20f845SMichael Walsh error_message += gp.sprint_var(invalid_values, gp.show_type()) 505da20f845SMichael Walsh error_message += gp.sprint_var(valid_values, gp.show_type()) 506da20f845SMichael Walsh error_message += gp.sprint_var(required_values, gp.show_type()) 50735026be5SMichael Walsh return process_error_message(error_message) 50835026be5SMichael Walsh 509018e25fbSMichael Walsh if type(var_value) is not list: 51089eff544SMichael Walsh var_name = get_var_name(var_name) 511018e25fbSMichael Walsh error_message = valid_type(var_value, list, var_name=var_name) 512018e25fbSMichael Walsh if error_message: 513018e25fbSMichael Walsh return process_error_message(error_message) 514018e25fbSMichael Walsh 515018e25fbSMichael Walsh if fail_on_empty and len(var_value) == 0: 51689eff544SMichael Walsh var_name = get_var_name(var_name) 517018e25fbSMichael Walsh error_message += "Invalid empty list:\n" 518018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 519018e25fbSMichael Walsh return process_error_message(error_message) 520ca193993SMichael Walsh 52135026be5SMichael Walsh if len(required_values): 52235026be5SMichael Walsh found_error = 0 52335026be5SMichael Walsh display_required_values = list(required_values) 52435026be5SMichael Walsh for ix in range(0, len(required_values)): 52535026be5SMichael Walsh if required_values[ix] not in var_value: 52635026be5SMichael Walsh found_error = 1 527*20f38712SPatrick Williams display_required_values[ix] = ( 52835026be5SMichael Walsh str(display_required_values[ix]) + "*" 529*20f38712SPatrick Williams ) 53035026be5SMichael Walsh if found_error: 53189eff544SMichael Walsh var_name = get_var_name(var_name) 53235026be5SMichael Walsh error_message += "The following list is invalid:\n" 533*20f38712SPatrick Williams error_message += gp.sprint_varx( 534*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 535*20f38712SPatrick Williams ) 53635026be5SMichael Walsh error_message += "\n" 53735026be5SMichael Walsh error_message += "Because some of the values in the " 53835026be5SMichael Walsh error_message += "required_values list are not present (see" 539*20f38712SPatrick Williams error_message += ' entries marked with "*"):\n' 54035026be5SMichael Walsh error_message += "\n" 541*20f38712SPatrick Williams error_message += gp.sprint_varx( 542*20f38712SPatrick Williams "required_values", 54335026be5SMichael Walsh display_required_values, 544*20f38712SPatrick Williams gp.blank() | gp.show_type(), 545*20f38712SPatrick Williams ) 54635026be5SMichael Walsh error_message += "\n" 54735026be5SMichael Walsh 54835026be5SMichael Walsh return process_error_message(error_message) 54935026be5SMichael Walsh 55035026be5SMichael Walsh if len(invalid_values): 55135026be5SMichael Walsh found_error = 0 55235026be5SMichael Walsh display_var_value = list(var_value) 55335026be5SMichael Walsh for ix in range(0, len(var_value)): 55435026be5SMichael Walsh if var_value[ix] in invalid_values: 55535026be5SMichael Walsh found_error = 1 55635026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 55735026be5SMichael Walsh 55835026be5SMichael Walsh if found_error: 55989eff544SMichael Walsh var_name = get_var_name(var_name) 56035026be5SMichael Walsh error_message += "The following list is invalid (see entries" 561*20f38712SPatrick Williams error_message += ' marked with "*"):\n' 562*20f38712SPatrick Williams error_message += gp.sprint_varx( 563*20f38712SPatrick Williams var_name, display_var_value, gp.blank() | gp.show_type() 564*20f38712SPatrick Williams ) 56535026be5SMichael Walsh error_message += "\n" 56635026be5SMichael Walsh error_message += gp.sprint_var(invalid_values, gp.show_type()) 56735026be5SMichael Walsh return process_error_message(error_message) 56835026be5SMichael Walsh 569ca193993SMichael Walsh found_error = 0 570ca193993SMichael Walsh display_var_value = list(var_value) 571ca193993SMichael Walsh for ix in range(0, len(var_value)): 572ca193993SMichael Walsh if var_value[ix] not in valid_values: 573ca193993SMichael Walsh found_error = 1 57435026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 575ca193993SMichael Walsh 576ca193993SMichael Walsh if found_error: 57789eff544SMichael Walsh var_name = get_var_name(var_name) 578018e25fbSMichael Walsh error_message += "The following list is invalid (see entries marked" 579*20f38712SPatrick Williams error_message += ' with "*"):\n' 580*20f38712SPatrick Williams error_message += gp.sprint_varx( 581*20f38712SPatrick Williams var_name, display_var_value, gp.blank() | gp.show_type() 582*20f38712SPatrick Williams ) 583018e25fbSMichael Walsh error_message += "\n" 58435026be5SMichael Walsh error_message += gp.sprint_var(valid_values, gp.show_type()) 585018e25fbSMichael Walsh return process_error_message(error_message) 586ca193993SMichael Walsh 587ca193993SMichael Walsh return process_error_message(error_message) 5887ac5fd81SMichael Walsh 5897ac5fd81SMichael Walsh 590*20f38712SPatrick Williamsdef valid_dict( 591*20f38712SPatrick Williams var_value, 592*20f38712SPatrick Williams required_keys=[], 593*20f38712SPatrick Williams valid_values={}, 594*20f38712SPatrick Williams invalid_values={}, 595*20f38712SPatrick Williams var_name=None, 596*20f38712SPatrick Williams): 5977ac5fd81SMichael Walsh r""" 59853902dd1SMichael Walsh The dictionary variable value is valid if it contains all required keys and each entry passes the 59953902dd1SMichael Walsh valid_value() call. 60053902dd1SMichael Walsh 60153902dd1SMichael Walsh Examples: 60253902dd1SMichael Walsh person_record = {'last_name': 'Jones', 'first_name': 'John'} 60353902dd1SMichael Walsh valid_values = {'last_name': ['Doe', 'Jones', 'Johnson'], 'first_name': ['John', 'Mary']} 60453902dd1SMichael Walsh invalid_values = {'last_name': ['Manson', 'Hitler', 'Presley'], 'first_name': ['Mickey', 'Goofy']} 60553902dd1SMichael Walsh 60653902dd1SMichael Walsh valid_dict(person_record, valid_values=valid_values) 60753902dd1SMichael Walsh valid_dict(person_record, invalid_values=invalid_values) 6087ac5fd81SMichael Walsh 609018e25fbSMichael Walsh Description of argument(s): 610018e25fbSMichael Walsh var_value The value being validated. 611da20f845SMichael Walsh required_keys A list of keys which must be found in the dictionary for it to be 612da20f845SMichael Walsh considered valid. 61353902dd1SMichael Walsh valid_values A dictionary whose entries correspond to the entries in var_value. Each 6148206851aSGeorge Keishing value in valid_values is itself a valid_values list for the corresponding 61553902dd1SMichael Walsh value in var_value. For any var_value[key] to be considered valid, its 61653902dd1SMichael Walsh value must be found in valid_values[key]. 61753902dd1SMichael Walsh 61853902dd1SMichael Walsh invalid_values A dictionary whose entries correspond to the entries in var_value. Each 61953902dd1SMichael Walsh value in invalid_values is itself an invalid_values list for the 62081384420SMichael Walsh corresponding value in var_value. For any var_value[key] to be 62181384420SMichael Walsh considered valid, its value must NOT be found in invalid_values[key]. 6227ac5fd81SMichael Walsh """ 6237ac5fd81SMichael Walsh 6247ac5fd81SMichael Walsh error_message = "" 625018e25fbSMichael Walsh missing_keys = list(set(required_keys) - set(var_value.keys())) 626018e25fbSMichael Walsh if len(missing_keys) > 0: 62789eff544SMichael Walsh var_name = get_var_name(var_name) 628018e25fbSMichael Walsh error_message += "The following dictionary is invalid because it is" 629018e25fbSMichael Walsh error_message += " missing required keys:\n" 630*20f38712SPatrick Williams error_message += gp.sprint_varx( 631*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 632*20f38712SPatrick Williams ) 633018e25fbSMichael Walsh error_message += "\n" 63435026be5SMichael Walsh error_message += gp.sprint_var(missing_keys, gp.show_type()) 6357ac5fd81SMichael Walsh return process_error_message(error_message) 636018e25fbSMichael Walsh 63753902dd1SMichael Walsh var_name = get_var_name(var_name) 63853902dd1SMichael Walsh if len(valid_values): 63953902dd1SMichael Walsh keys = valid_values.keys() 640*20f38712SPatrick Williams error_message = valid_dict( 641*20f38712SPatrick Williams var_value, required_keys=keys, var_name=var_name 642*20f38712SPatrick Williams ) 64353902dd1SMichael Walsh if error_message: 64453902dd1SMichael Walsh return process_error_message(error_message) 64553902dd1SMichael Walsh for key, value in valid_values.items(): 64653902dd1SMichael Walsh key_name = " [" + key + "]" 647*20f38712SPatrick Williams sub_error_message = valid_value( 648*20f38712SPatrick Williams var_value[key], valid_values=value, var_name=key_name 649*20f38712SPatrick Williams ) 65053902dd1SMichael Walsh if sub_error_message: 651*20f38712SPatrick Williams error_message += ( 652*20f38712SPatrick Williams "The following dictionary is invalid because one of its" 653*20f38712SPatrick Williams " entries is invalid:\n" 654*20f38712SPatrick Williams ) 655*20f38712SPatrick Williams error_message += gp.sprint_varx( 656*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 657*20f38712SPatrick Williams ) 65853902dd1SMichael Walsh error_message += "\n" 65953902dd1SMichael Walsh error_message += sub_error_message 66053902dd1SMichael Walsh return process_error_message(error_message) 66153902dd1SMichael Walsh 66253902dd1SMichael Walsh for key, value in invalid_values.items(): 66353902dd1SMichael Walsh if key not in var_value: 66453902dd1SMichael Walsh continue 66553902dd1SMichael Walsh key_name = " [" + key + "]" 666*20f38712SPatrick Williams sub_error_message = valid_value( 667*20f38712SPatrick Williams var_value[key], invalid_values=value, var_name=key_name 668*20f38712SPatrick Williams ) 66953902dd1SMichael Walsh if sub_error_message: 670*20f38712SPatrick Williams error_message += ( 671*20f38712SPatrick Williams "The following dictionary is invalid because one of its" 672*20f38712SPatrick Williams " entries is invalid:\n" 673*20f38712SPatrick Williams ) 674*20f38712SPatrick Williams error_message += gp.sprint_varx( 675*20f38712SPatrick Williams var_name, var_value, gp.blank() | gp.show_type() 676*20f38712SPatrick Williams ) 67753902dd1SMichael Walsh error_message += "\n" 67853902dd1SMichael Walsh error_message += sub_error_message 67953902dd1SMichael Walsh return process_error_message(error_message) 68053902dd1SMichael Walsh 68153902dd1SMichael Walsh return process_error_message(error_message) 68253902dd1SMichael Walsh 683018e25fbSMichael Walsh 68489eff544SMichael Walshdef valid_program(var_value, var_name=None): 685be3a8150SMichael Walsh r""" 686da20f845SMichael Walsh The variable value is valid if it contains the name of a program which can be located using the "which" 687da20f845SMichael Walsh command. 688be3a8150SMichael Walsh 689be3a8150SMichael Walsh Description of argument(s): 690be3a8150SMichael Walsh var_value The value being validated. 691be3a8150SMichael Walsh """ 692be3a8150SMichael Walsh 693be3a8150SMichael Walsh error_message = "" 694*20f38712SPatrick Williams rc, out_buf = gc.shell_cmd( 695*20f38712SPatrick Williams "which " + var_value, quiet=1, show_err=0, ignore_err=1 696*20f38712SPatrick Williams ) 697be3a8150SMichael Walsh if rc: 69889eff544SMichael Walsh var_name = get_var_name(var_name) 699be3a8150SMichael Walsh error_message += "The following required program could not be found" 700be3a8150SMichael Walsh error_message += " using the $PATH environment variable:\n" 70100244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 702be3a8150SMichael Walsh PATH = os.environ.get("PATH", "").split(":") 703be3a8150SMichael Walsh error_message += "\n" 704be3a8150SMichael Walsh error_message += gp.sprint_var(PATH) 705be3a8150SMichael Walsh return process_error_message(error_message) 706be3a8150SMichael Walsh 707be3a8150SMichael Walsh 70889eff544SMichael Walshdef valid_length(var_value, min_length=None, max_length=None, var_name=None): 709b9d8dfd2SMichael Walsh r""" 710da20f845SMichael Walsh The variable value is valid if it is an object (e.g. list, dictionary) whose length is within the 711da20f845SMichael Walsh specified range. 712b9d8dfd2SMichael Walsh 713b9d8dfd2SMichael Walsh Description of argument(s): 714b9d8dfd2SMichael Walsh var_value The value being validated. 715da20f845SMichael Walsh min_length The minimum length of the object. If not None, the length of var_value 716da20f845SMichael Walsh must be greater than or equal to min_length. 717da20f845SMichael Walsh max_length The maximum length of the object. If not None, the length of var_value 718da20f845SMichael Walsh must be less than or equal to min_length. 719b9d8dfd2SMichael Walsh """ 720b9d8dfd2SMichael Walsh 721b9d8dfd2SMichael Walsh error_message = "" 722b9d8dfd2SMichael Walsh length = len(var_value) 723b9d8dfd2SMichael Walsh error_message = valid_range(length, min_length, max_length) 724b9d8dfd2SMichael Walsh if error_message: 72589eff544SMichael Walsh var_name = get_var_name(var_name) 726b9d8dfd2SMichael Walsh error_message = "The length of the following object is not within the" 727b9d8dfd2SMichael Walsh error_message += " expected range:\n" 728da20f845SMichael Walsh error_message += gp.sprint_vars(min_length, max_length) 729b9d8dfd2SMichael Walsh error_message += gp.sprint_var(length) 730b9d8dfd2SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 731b9d8dfd2SMichael Walsh error_message += "\n" 732b9d8dfd2SMichael Walsh return process_error_message(error_message) 733b9d8dfd2SMichael Walsh 734b9d8dfd2SMichael Walsh return process_error_message(error_message) 735b9d8dfd2SMichael Walsh 736b9d8dfd2SMichael Walsh 737018e25fbSMichael Walsh# Modify selected function docstrings by adding headers/footers. 738018e25fbSMichael Walsh 739018e25fbSMichael Walshfunc_names = [ 740*20f38712SPatrick Williams "valid_type", 741*20f38712SPatrick Williams "valid_value", 742*20f38712SPatrick Williams "valid_range", 743*20f38712SPatrick Williams "valid_integer", 744*20f38712SPatrick Williams "valid_dir_path", 745*20f38712SPatrick Williams "valid_file_path", 746*20f38712SPatrick Williams "valid_path", 747*20f38712SPatrick Williams "valid_list", 748*20f38712SPatrick Williams "valid_dict", 749*20f38712SPatrick Williams "valid_program", 750*20f38712SPatrick Williams "valid_length", 751*20f38712SPatrick Williams "valid_float", 752*20f38712SPatrick Williams "valid_date_time", 753018e25fbSMichael Walsh] 754018e25fbSMichael Walsh 755018e25fbSMichael Walshraw_doc_strings = {} 756018e25fbSMichael Walsh 757018e25fbSMichael Walshfor func_name in func_names: 758018e25fbSMichael Walsh cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name 759018e25fbSMichael Walsh cmd_buf += ".__doc__" 760018e25fbSMichael Walsh exec(cmd_buf) 761018e25fbSMichael Walsh cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name 762*20f38712SPatrick Williams cmd_buf += '.__doc__.rstrip(" \\n") + additional_args_docstring_footer' 763018e25fbSMichael Walsh exec(cmd_buf) 764