17423c01aSMichael Walsh#!/usr/bin/env python 27423c01aSMichael Walsh 37423c01aSMichael Walshr""" 4da20f845SMichael WalshThis module provides validation functions like valid_value(), valid_integer(), etc. 57423c01aSMichael Walsh""" 67423c01aSMichael Walsh 778bdfdd6SMichael Walshimport os 87423c01aSMichael Walshimport gen_print as gp 9be3a8150SMichael Walshimport gen_cmd as gc 10018e25fbSMichael Walshimport func_args as fa 118333a18dSMichael Walshimport datetime 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 20da20f845SMichael Walsh If exit_on_error is set, validation functions like valid_value() will exit the program on error instead 21da20f845SMichael Walsh 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 3189eff544SMichael Walshdef get_var_name(var_name): 32e23b5ad3SMichael Walsh r""" 33da20f845SMichael Walsh If var_name is not None, simply return its value. Otherwise, get the variable name of the first argument 34da20f845SMichael Walsh used to call the validation function (e.g. valid, valid_integer, etc.) and return it. 35e23b5ad3SMichael Walsh 36e23b5ad3SMichael Walsh This function is designed solely for use by other functions in this file. 37e23b5ad3SMichael Walsh 38e23b5ad3SMichael Walsh Example: 39e23b5ad3SMichael Walsh 40e23b5ad3SMichael Walsh A programmer codes this: 41e23b5ad3SMichael Walsh 42e23b5ad3SMichael Walsh valid_value(last_name) 43e23b5ad3SMichael Walsh 44e23b5ad3SMichael Walsh Which results in the following call stack: 45e23b5ad3SMichael Walsh 46e23b5ad3SMichael Walsh valid_value(last_name) 47e23b5ad3SMichael Walsh -> get_var_name(var_name) 48e23b5ad3SMichael Walsh 49e23b5ad3SMichael Walsh In this example, this function will return "last_name". 50e23b5ad3SMichael Walsh 51e23b5ad3SMichael Walsh Example: 52e23b5ad3SMichael Walsh 53018e25fbSMichael Walsh err_msg = valid_value(last_name, var_name="some_other_name") 54e23b5ad3SMichael Walsh 55e23b5ad3SMichael Walsh Which results in the following call stack: 56e23b5ad3SMichael Walsh 57018e25fbSMichael Walsh valid_value(var_value, var_name="some_other_name") 58e23b5ad3SMichael Walsh -> get_var_name(var_name) 59e23b5ad3SMichael Walsh 60e23b5ad3SMichael Walsh In this example, this function will return "some_other_name". 61e23b5ad3SMichael Walsh 62e23b5ad3SMichael Walsh Description of argument(s): 63e23b5ad3SMichael Walsh var_name The name of the variable. 64e23b5ad3SMichael Walsh """ 65e23b5ad3SMichael Walsh 6689eff544SMichael Walsh return var_name or gp.get_arg_name(0, 1, stack_frame_ix=3) 67e23b5ad3SMichael Walsh 68e23b5ad3SMichael Walsh 69e23b5ad3SMichael Walshdef process_error_message(error_message): 70e23b5ad3SMichael Walsh r""" 71018e25fbSMichael Walsh Process the error_message in the manner described below. 72e23b5ad3SMichael Walsh 73018e25fbSMichael Walsh This function is designed solely for use by other functions in this file. 74018e25fbSMichael Walsh 75018e25fbSMichael Walsh NOTE: A blank error_message means that there is no error. 76018e25fbSMichael Walsh 77da20f845SMichael Walsh For the following explanations, assume the caller of this function is a function with the following 78da20f845SMichael Walsh definition: 7989eff544SMichael Walsh valid_value(var_value, valid_values=[], invalid_values=[], var_name=None): 80018e25fbSMichael Walsh 81da20f845SMichael Walsh If the user of valid_value() is assigning the valid_value() return value to a variable, 82da20f845SMichael Walsh process_error_message() will simply return the error_message. This mode of usage is illustrated by the 83da20f845SMichael Walsh following example: 84018e25fbSMichael Walsh 85018e25fbSMichael Walsh error_message = valid_value(var1) 86018e25fbSMichael Walsh 87da20f845SMichael Walsh This mode is useful for callers who wish to validate a variable and then decide for themselves what to do 88da20f845SMichael Walsh with the error_message (e.g. raise(error_message), BuiltIn().fail(error_message), etc.). 89018e25fbSMichael Walsh 90da20f845SMichael Walsh If the user of valid_value() is NOT assigning the valid_value() return value to a variable, 91da20f845SMichael Walsh process_error_message() will behave as follows. 92018e25fbSMichael Walsh 93da20f845SMichael Walsh First, if error_message is non-blank, it will be printed to stderr via a call to 94da20f845SMichael Walsh gp.print_error_report(error_message). 95018e25fbSMichael Walsh 96018e25fbSMichael Walsh If exit_on_error is set: 97018e25fbSMichael Walsh - If the error_message is blank, simply return. 98da20f845SMichael Walsh - If the error_message is non-blank, exit the program with a return code of 1. 99018e25fbSMichael Walsh 100018e25fbSMichael Walsh If exit_on_error is NOT set: 101018e25fbSMichael Walsh - If the error_message is blank, return True. 102018e25fbSMichael Walsh - If the error_message is non-blank, return False. 103e23b5ad3SMichael Walsh 104e23b5ad3SMichael Walsh Description of argument(s): 105e23b5ad3SMichael Walsh error_message An error message. 106e23b5ad3SMichael Walsh """ 107e23b5ad3SMichael Walsh 108da20f845SMichael Walsh # Determine whether the caller's caller is assigning the result to a variable. 109018e25fbSMichael Walsh l_value = gp.get_arg_name(None, -1, stack_frame_ix=3) 110018e25fbSMichael Walsh if l_value: 111018e25fbSMichael Walsh return error_message 112018e25fbSMichael Walsh 113e23b5ad3SMichael Walsh if error_message == "": 114018e25fbSMichael Walsh if exit_on_error: 115018e25fbSMichael Walsh return 116e23b5ad3SMichael Walsh return True 117e23b5ad3SMichael Walsh 118018e25fbSMichael Walsh gp.print_error_report(error_message, stack_frame_ix=4) 119e23b5ad3SMichael Walsh if exit_on_error: 12010a4d98bSMichael Walsh exit(1) 121e23b5ad3SMichael Walsh return False 122e23b5ad3SMichael Walsh 1237423c01aSMichael Walsh 124da20f845SMichael Walsh# Note to programmers: All of the validation functions in this module should follow the same basic template: 12589eff544SMichael Walsh# def valid_value(var_value, var1, var2, varn, var_name=None): 126018e25fbSMichael Walsh# 127018e25fbSMichael Walsh# error_message = "" 128018e25fbSMichael Walsh# if not valid: 12989eff544SMichael Walsh# var_name = get_var_name(var_name) 130018e25fbSMichael Walsh# error_message += "The following variable is invalid because...:\n" 131018e25fbSMichael Walsh# error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 132018e25fbSMichael Walsh# 133018e25fbSMichael Walsh# return process_error_message(error_message) 1347423c01aSMichael Walsh 135018e25fbSMichael Walsh 136da20f845SMichael Walsh# The docstring header and footer will be added to each validation function's existing docstring. 137018e25fbSMichael Walshdocstring_header = \ 138018e25fbSMichael Walsh 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 146018e25fbSMichael Walshadditional_args_docstring_footer = \ 147018e25fbSMichael Walsh r""" 148da20f845SMichael Walsh var_name The name of the variable whose value is passed in var_value. For the 149da20f845SMichael Walsh general case, this argument is unnecessary as this function can figure 150da20f845SMichael Walsh out the var_name. This is provided for Robot callers in which case, this 151da20f845SMichael Walsh function lacks the ability to determine the variable name. 152018e25fbSMichael Walsh """ 153018e25fbSMichael Walsh 154018e25fbSMichael Walsh 15589eff544SMichael Walshdef valid_type(var_value, required_type, var_name=None): 156018e25fbSMichael Walsh r""" 157018e25fbSMichael Walsh The variable value is valid if it is of the required type. 158018e25fbSMichael Walsh 159018e25fbSMichael Walsh Examples: 160018e25fbSMichael Walsh 161018e25fbSMichael Walsh valid_type(var1, int) 162018e25fbSMichael Walsh 163018e25fbSMichael Walsh valid_type(var1, (list, dict)) 164018e25fbSMichael Walsh 165018e25fbSMichael Walsh Description of argument(s): 166018e25fbSMichael Walsh var_value The value being validated. 167da20f845SMichael Walsh required_type A type or a tuple of types (e.g. str, int, etc.). 168018e25fbSMichael Walsh """ 169018e25fbSMichael Walsh 170018e25fbSMichael Walsh error_message = "" 171018e25fbSMichael Walsh if type(required_type) is tuple: 172018e25fbSMichael Walsh if type(var_value) in required_type: 173018e25fbSMichael Walsh return process_error_message(error_message) 174018e25fbSMichael Walsh else: 175018e25fbSMichael Walsh if type(var_value) is required_type: 176018e25fbSMichael Walsh return process_error_message(error_message) 177018e25fbSMichael Walsh 178018e25fbSMichael Walsh # If we get to this point, the validation has failed. 17989eff544SMichael Walsh var_name = get_var_name(var_name) 180018e25fbSMichael Walsh error_message += "Invalid variable type:\n" 181018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 182018e25fbSMichael Walsh gp.blank() | gp.show_type()) 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 191018e25fbSMichael Walsh r""" 192da20f845SMichael Walsh The variable value is valid if it is either contained in the valid_values list or if it is NOT contained 193da20f845SMichael Walsh in the invalid_values list. If the caller specifies nothing for either of these 2 arguments, 194da20f845SMichael Walsh invalid_values will be initialized to ['', None]. This is a good way to fail on variables which contain 195da20f845SMichael Walsh blank values. 196018e25fbSMichael Walsh 197018e25fbSMichael Walsh It is illegal to specify both valid_values and invalid values. 198018e25fbSMichael Walsh 199018e25fbSMichael Walsh Example: 200018e25fbSMichael Walsh 201018e25fbSMichael Walsh var1 = '' 202018e25fbSMichael Walsh valid_value(var1) 203018e25fbSMichael Walsh 204da20f845SMichael Walsh This code would fail because var1 is blank and the default value for invalid_values is ['', None]. 205018e25fbSMichael Walsh 206018e25fbSMichael Walsh Example: 207018e25fbSMichael Walsh var1 = 'yes' 208018e25fbSMichael Walsh valid_value(var1, valid_values=['yes', 'true']) 209018e25fbSMichael Walsh 210018e25fbSMichael Walsh This code would pass. 211018e25fbSMichael Walsh 212018e25fbSMichael Walsh Description of argument(s): 213018e25fbSMichael Walsh var_value The value being validated. 214da20f845SMichael Walsh valid_values A list of valid values. The variable value must be equal to one of these 215da20f845SMichael Walsh values to be considered valid. 216da20f845SMichael Walsh invalid_values A list of invalid values. If the variable value is equal to any of 217da20f845SMichael Walsh these, it is considered invalid. 218018e25fbSMichael Walsh """ 219018e25fbSMichael Walsh 220bec416ddSMichael Walsh error_message = "" 221bec416ddSMichael Walsh 222e23b5ad3SMichael Walsh # Validate this function's arguments. 2237423c01aSMichael Walsh len_valid_values = len(valid_values) 2247423c01aSMichael Walsh len_invalid_values = len(invalid_values) 2257423c01aSMichael Walsh if len_valid_values > 0 and len_invalid_values > 0: 226018e25fbSMichael Walsh error_message += "Programmer error - You must provide either an" 227018e25fbSMichael Walsh error_message += " invalid_values list or a valid_values" 228018e25fbSMichael Walsh error_message += " list but NOT both:\n" 229018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values) 230018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values) 231018e25fbSMichael Walsh return process_error_message(error_message) 2327423c01aSMichael Walsh 2330f5fa532SMichael Walsh error_message = valid_type(valid_values, list, var_name='valid_values') 2340f5fa532SMichael Walsh if error_message: 2350f5fa532SMichael Walsh return process_error_message(error_message) 2360f5fa532SMichael Walsh 2370f5fa532SMichael Walsh error_message = valid_type(invalid_values, list, var_name='invalid_values') 2380f5fa532SMichael Walsh if error_message: 2390f5fa532SMichael Walsh return process_error_message(error_message) 2400f5fa532SMichael Walsh 2417423c01aSMichael Walsh if len_valid_values > 0: 2427423c01aSMichael Walsh # Processing the valid_values list. 2437423c01aSMichael Walsh if var_value in valid_values: 244018e25fbSMichael Walsh return process_error_message(error_message) 24589eff544SMichael Walsh var_name = get_var_name(var_name) 246018e25fbSMichael Walsh error_message += "Invalid variable value:\n" 247018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 248018e25fbSMichael Walsh gp.blank() | gp.verbose() 249018e25fbSMichael Walsh | gp.show_type()) 250018e25fbSMichael Walsh error_message += "\n" 251018e25fbSMichael Walsh error_message += "It must be one of the following values:\n" 252018e25fbSMichael Walsh error_message += "\n" 253018e25fbSMichael Walsh error_message += gp.sprint_var(valid_values, 254018e25fbSMichael Walsh gp.blank() | gp.show_type()) 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" 267018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 268018e25fbSMichael Walsh gp.blank() | gp.verbose() 269018e25fbSMichael Walsh | gp.show_type()) 270018e25fbSMichael Walsh error_message += "\n" 27153902dd1SMichael Walsh error_message += "It must NOT be any of the following values:\n" 272018e25fbSMichael Walsh error_message += "\n" 273018e25fbSMichael Walsh error_message += gp.sprint_var(invalid_values, 274018e25fbSMichael Walsh gp.blank() | gp.show_type()) 275e23b5ad3SMichael Walsh return process_error_message(error_message) 2767423c01aSMichael Walsh 277bec416ddSMichael Walsh 27889eff544SMichael Walshdef valid_range(var_value, lower=None, upper=None, var_name=None): 279bec416ddSMichael Walsh r""" 280018e25fbSMichael Walsh The variable value is valid if it is within the specified range. 281bec416ddSMichael Walsh 282da20f845SMichael Walsh This function can be used with any type of operands where they can have a greater than/less than 283da20f845SMichael Walsh relationship to each other (e.g. int, float, str). 284018e25fbSMichael Walsh 285018e25fbSMichael Walsh Description of argument(s): 286bec416ddSMichael Walsh var_value The value being validated. 287da20f845SMichael Walsh lower The lower end of the range. If not None, the var_value must be greater 288da20f845SMichael Walsh than or equal to lower. 289da20f845SMichael Walsh upper The upper end of the range. If not None, the var_value must be less than 290da20f845SMichael Walsh or equal to upper. 291bec416ddSMichael Walsh """ 292bec416ddSMichael Walsh 293bec416ddSMichael Walsh error_message = "" 294b9d8dfd2SMichael Walsh if lower is None and upper is None: 295018e25fbSMichael Walsh return process_error_message(error_message) 296b9d8dfd2SMichael Walsh if lower is None and var_value <= upper: 297018e25fbSMichael Walsh return process_error_message(error_message) 298b9d8dfd2SMichael Walsh if upper is None and var_value >= lower: 299018e25fbSMichael Walsh return process_error_message(error_message) 300018e25fbSMichael Walsh if lower and upper: 301018e25fbSMichael Walsh if lower > upper: 30289eff544SMichael Walsh var_name = get_var_name(var_name) 303018e25fbSMichael Walsh error_message += "Programmer error - the lower value is greater" 304018e25fbSMichael Walsh error_message += " than the upper value:\n" 305018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type()) 306018e25fbSMichael Walsh return process_error_message(error_message) 307018e25fbSMichael Walsh if lower <= var_value <= upper: 308018e25fbSMichael Walsh return process_error_message(error_message) 309bec416ddSMichael Walsh 31089eff544SMichael Walsh var_name = get_var_name(var_name) 311018e25fbSMichael Walsh error_message += "The following variable is not within the expected" 312018e25fbSMichael Walsh error_message += " range:\n" 313018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 314018e25fbSMichael Walsh error_message += "\n" 315018e25fbSMichael Walsh error_message += "range:\n" 316018e25fbSMichael Walsh error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2) 317e23b5ad3SMichael Walsh return process_error_message(error_message) 3187423c01aSMichael Walsh 31978bdfdd6SMichael Walsh 32089eff544SMichael Walshdef valid_integer(var_value, lower=None, upper=None, var_name=None): 32178bdfdd6SMichael Walsh r""" 322da20f845SMichael Walsh The variable value is valid if it is an integer or can be interpreted as an integer (e.g. 7, "7", etc.). 32378bdfdd6SMichael Walsh 324da20f845SMichael Walsh This function also calls valid_range to make sure the integer value is within the specified range (if 325da20f845SMichael Walsh any). 326018e25fbSMichael Walsh 327018e25fbSMichael Walsh Description of argument(s): 32878bdfdd6SMichael Walsh var_value The value being validated. 329da20f845SMichael Walsh lower The lower end of the range. If not None, the var_value must be greater 330da20f845SMichael Walsh than or equal to lower. 331da20f845SMichael Walsh upper The upper end of the range. If not None, the var_value must be less than 332da20f845SMichael Walsh or equal to upper. 333018e25fbSMichael Walsh """ 334018e25fbSMichael Walsh 335018e25fbSMichael Walsh error_message = "" 33689eff544SMichael Walsh var_name = get_var_name(var_name) 337018e25fbSMichael Walsh try: 338018e25fbSMichael Walsh var_value = int(str(var_value), 0) 339018e25fbSMichael Walsh except ValueError: 340018e25fbSMichael Walsh error_message += "Invalid integer value:\n" 341018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 342018e25fbSMichael Walsh gp.blank() | gp.show_type()) 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" 3768333a18dSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 3778333a18dSMichael Walsh gp.blank() | gp.show_type()) 3788333a18dSMichael Walsh return process_error_message(error_message) 3798333a18dSMichael Walsh 3808333a18dSMichael Walsh # Check the range (if any). 3818333a18dSMichael Walsh if lower: 3828333a18dSMichael Walsh lower = float(str(lower)) 3838333a18dSMichael Walsh if upper: 3848333a18dSMichael Walsh upper = float(str(upper)) 3858333a18dSMichael Walsh error_message = valid_range(var_value, lower, upper, var_name=var_name) 3868333a18dSMichael Walsh 3878333a18dSMichael Walsh return process_error_message(error_message) 3888333a18dSMichael Walsh 3898333a18dSMichael Walsh 3908333a18dSMichael Walshdef valid_date_time(var_value, var_name=None): 3918333a18dSMichael Walsh r""" 3928333a18dSMichael Walsh The variable value is valid if it can be interpreted as a date/time (e.g. "14:49:49.981", "tomorrow", 3938333a18dSMichael Walsh etc.) by the linux date command. 3948333a18dSMichael Walsh 3958333a18dSMichael Walsh Description of argument(s): 3968333a18dSMichael Walsh var_value The value being validated. 3978333a18dSMichael Walsh """ 3988333a18dSMichael Walsh 3998333a18dSMichael Walsh error_message = "" 4008333a18dSMichael Walsh rc, out_buf = gc.shell_cmd("date -d '" + str(var_value) + "'", quiet=1, show_err=0, ignore_err=1) 4018333a18dSMichael Walsh if rc: 4028333a18dSMichael Walsh var_name = get_var_name(var_name) 4038333a18dSMichael Walsh error_message += "Invalid date/time value:\n" 4048333a18dSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 4058333a18dSMichael Walsh gp.blank() | gp.show_type()) 4068333a18dSMichael Walsh return process_error_message(error_message) 4078333a18dSMichael Walsh 4088333a18dSMichael Walsh return process_error_message(error_message) 4098333a18dSMichael Walsh 4108333a18dSMichael Walsh 41189eff544SMichael Walshdef valid_dir_path(var_value, var_name=None): 412018e25fbSMichael Walsh r""" 413da20f845SMichael Walsh The variable value is valid if it contains the path of an existing directory. 414018e25fbSMichael Walsh 415018e25fbSMichael Walsh Description of argument(s): 416018e25fbSMichael Walsh var_value The value being validated. 41778bdfdd6SMichael Walsh """ 41878bdfdd6SMichael Walsh 41978bdfdd6SMichael Walsh error_message = "" 42078bdfdd6SMichael Walsh if not os.path.isdir(str(var_value)): 42189eff544SMichael Walsh var_name = get_var_name(var_name) 422018e25fbSMichael Walsh error_message += "The following directory does not exist:\n" 42300244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 42478bdfdd6SMichael Walsh 425e23b5ad3SMichael Walsh return process_error_message(error_message) 42678bdfdd6SMichael Walsh 42778bdfdd6SMichael Walsh 42889eff544SMichael Walshdef valid_file_path(var_value, var_name=None): 42978bdfdd6SMichael Walsh r""" 430018e25fbSMichael Walsh The variable value is valid if it contains the path of an existing file. 43178bdfdd6SMichael Walsh 432018e25fbSMichael Walsh Description of argument(s): 43378bdfdd6SMichael Walsh var_value The value being validated. 43478bdfdd6SMichael Walsh """ 43578bdfdd6SMichael Walsh 43678bdfdd6SMichael Walsh error_message = "" 43778bdfdd6SMichael Walsh if not os.path.isfile(str(var_value)): 43889eff544SMichael Walsh var_name = get_var_name(var_name) 439018e25fbSMichael Walsh error_message += "The following file does not exist:\n" 44000244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 44178bdfdd6SMichael Walsh 442e23b5ad3SMichael Walsh return process_error_message(error_message) 44378bdfdd6SMichael Walsh 44478bdfdd6SMichael Walsh 44589eff544SMichael Walshdef valid_path(var_value, var_name=None): 446e23b5ad3SMichael Walsh r""" 447da20f845SMichael Walsh The variable value is valid if it contains the path of an existing file or directory. 448e23b5ad3SMichael Walsh 449018e25fbSMichael Walsh Description of argument(s): 450e23b5ad3SMichael Walsh var_value The value being validated. 451e23b5ad3SMichael Walsh """ 452e23b5ad3SMichael Walsh 453e23b5ad3SMichael Walsh error_message = "" 454e23b5ad3SMichael Walsh if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))): 45589eff544SMichael Walsh var_name = get_var_name(var_name) 456018e25fbSMichael Walsh error_message += "Invalid path (file or directory does not exist):\n" 45700244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 458e23b5ad3SMichael Walsh 459e23b5ad3SMichael Walsh return process_error_message(error_message) 4602c687e98SMichael Walsh 4612c687e98SMichael Walsh 46235026be5SMichael Walshdef valid_list(var_value, valid_values=[], invalid_values=[], 46389eff544SMichael Walsh required_values=[], fail_on_empty=False, var_name=None): 4642c687e98SMichael Walsh r""" 465da20f845SMichael Walsh The variable value is valid if it is a list where each entry can be found in the valid_values list or if 466da20f845SMichael Walsh none of its values can be found in the invalid_values list or if all of the values in the required_values 467da20f845SMichael Walsh list can be found in var_value. 46835026be5SMichael Walsh 469da20f845SMichael Walsh The caller may only specify one of these 3 arguments: valid_values, invalid_values, required_values. 4702c687e98SMichael Walsh 471018e25fbSMichael Walsh Description of argument(s): 472018e25fbSMichael Walsh var_value The value being validated. 473da20f845SMichael Walsh valid_values A list of valid values. Each element in the var_value list must be equal 474da20f845SMichael Walsh to one of these values to be considered valid. 475da20f845SMichael Walsh invalid_values A list of invalid values. If any element in var_value is equal to any of 476da20f845SMichael Walsh the values in this argument, var_value is considered invalid. 477da20f845SMichael Walsh required_values Every value in required_values must be found in var_value. Otherwise, 478da20f845SMichael Walsh var_value is considered invalid. 479da20f845SMichael Walsh fail_on_empty Indicates that an empty list for the variable value should be considered 480da20f845SMichael Walsh an error. 481ca193993SMichael Walsh """ 482ca193993SMichael Walsh 483ca193993SMichael Walsh error_message = "" 484018e25fbSMichael Walsh 48535026be5SMichael Walsh # Validate this function's arguments. 486da20f845SMichael Walsh if not (bool(len(valid_values)) ^ bool(len(invalid_values)) ^ bool(len(required_values))): 48735026be5SMichael Walsh error_message += "Programmer error - You must provide only one of the" 48835026be5SMichael Walsh error_message += " following: valid_values, invalid_values," 48935026be5SMichael Walsh error_message += " required_values.\n" 490da20f845SMichael Walsh error_message += gp.sprint_var(invalid_values, gp.show_type()) 491da20f845SMichael Walsh error_message += gp.sprint_var(valid_values, gp.show_type()) 492da20f845SMichael Walsh error_message += gp.sprint_var(required_values, gp.show_type()) 49335026be5SMichael Walsh return process_error_message(error_message) 49435026be5SMichael Walsh 495018e25fbSMichael Walsh if type(var_value) is not list: 49689eff544SMichael Walsh var_name = get_var_name(var_name) 497018e25fbSMichael Walsh error_message = valid_type(var_value, list, var_name=var_name) 498018e25fbSMichael Walsh if error_message: 499018e25fbSMichael Walsh return process_error_message(error_message) 500018e25fbSMichael Walsh 501018e25fbSMichael Walsh if fail_on_empty and len(var_value) == 0: 50289eff544SMichael Walsh var_name = get_var_name(var_name) 503018e25fbSMichael Walsh error_message += "Invalid empty list:\n" 504018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) 505018e25fbSMichael Walsh return process_error_message(error_message) 506ca193993SMichael Walsh 50735026be5SMichael Walsh if len(required_values): 50835026be5SMichael Walsh found_error = 0 50935026be5SMichael Walsh display_required_values = list(required_values) 51035026be5SMichael Walsh for ix in range(0, len(required_values)): 51135026be5SMichael Walsh if required_values[ix] not in var_value: 51235026be5SMichael Walsh found_error = 1 51335026be5SMichael Walsh display_required_values[ix] = \ 51435026be5SMichael Walsh str(display_required_values[ix]) + "*" 51535026be5SMichael Walsh if found_error: 51689eff544SMichael Walsh var_name = get_var_name(var_name) 51735026be5SMichael Walsh error_message += "The following list is invalid:\n" 51835026be5SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, 51935026be5SMichael Walsh gp.blank() | gp.show_type()) 52035026be5SMichael Walsh error_message += "\n" 52135026be5SMichael Walsh error_message += "Because some of the values in the " 52235026be5SMichael Walsh error_message += "required_values list are not present (see" 52335026be5SMichael Walsh error_message += " entries marked with \"*\"):\n" 52435026be5SMichael Walsh error_message += "\n" 52535026be5SMichael Walsh error_message += gp.sprint_varx('required_values', 52635026be5SMichael Walsh display_required_values, 52735026be5SMichael Walsh gp.blank() | gp.show_type()) 52835026be5SMichael Walsh error_message += "\n" 52935026be5SMichael Walsh 53035026be5SMichael Walsh return process_error_message(error_message) 53135026be5SMichael Walsh 53235026be5SMichael Walsh if len(invalid_values): 53335026be5SMichael Walsh found_error = 0 53435026be5SMichael Walsh display_var_value = list(var_value) 53535026be5SMichael Walsh for ix in range(0, len(var_value)): 53635026be5SMichael Walsh if var_value[ix] in invalid_values: 53735026be5SMichael Walsh found_error = 1 53835026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 53935026be5SMichael Walsh 54035026be5SMichael Walsh if found_error: 54189eff544SMichael Walsh var_name = get_var_name(var_name) 54235026be5SMichael Walsh error_message += "The following list is invalid (see entries" 54335026be5SMichael Walsh error_message += " marked with \"*\"):\n" 54435026be5SMichael Walsh error_message += gp.sprint_varx(var_name, display_var_value, 54535026be5SMichael Walsh gp.blank() | gp.show_type()) 54635026be5SMichael Walsh error_message += "\n" 54735026be5SMichael Walsh error_message += gp.sprint_var(invalid_values, gp.show_type()) 54835026be5SMichael Walsh return process_error_message(error_message) 54935026be5SMichael Walsh 550ca193993SMichael Walsh found_error = 0 551ca193993SMichael Walsh display_var_value = list(var_value) 552ca193993SMichael Walsh for ix in range(0, len(var_value)): 553ca193993SMichael Walsh if var_value[ix] not in valid_values: 554ca193993SMichael Walsh found_error = 1 55535026be5SMichael Walsh display_var_value[ix] = str(var_value[ix]) + "*" 556ca193993SMichael Walsh 557ca193993SMichael Walsh if found_error: 55889eff544SMichael Walsh var_name = get_var_name(var_name) 559018e25fbSMichael Walsh error_message += "The following list is invalid (see entries marked" 560018e25fbSMichael Walsh error_message += " with \"*\"):\n" 561018e25fbSMichael Walsh error_message += gp.sprint_varx(var_name, display_var_value, 562018e25fbSMichael Walsh gp.blank() | gp.show_type()) 563018e25fbSMichael Walsh error_message += "\n" 56435026be5SMichael Walsh error_message += gp.sprint_var(valid_values, gp.show_type()) 565018e25fbSMichael Walsh return process_error_message(error_message) 566ca193993SMichael Walsh 567ca193993SMichael Walsh return process_error_message(error_message) 5687ac5fd81SMichael Walsh 5697ac5fd81SMichael Walsh 57053902dd1SMichael Walshdef valid_dict(var_value, required_keys=[], valid_values={}, invalid_values={}, var_name=None): 5717ac5fd81SMichael Walsh r""" 57253902dd1SMichael Walsh The dictionary variable value is valid if it contains all required keys and each entry passes the 57353902dd1SMichael Walsh valid_value() call. 57453902dd1SMichael Walsh 57553902dd1SMichael Walsh Examples: 57653902dd1SMichael Walsh person_record = {'last_name': 'Jones', 'first_name': 'John'} 57753902dd1SMichael Walsh valid_values = {'last_name': ['Doe', 'Jones', 'Johnson'], 'first_name': ['John', 'Mary']} 57853902dd1SMichael Walsh invalid_values = {'last_name': ['Manson', 'Hitler', 'Presley'], 'first_name': ['Mickey', 'Goofy']} 57953902dd1SMichael Walsh 58053902dd1SMichael Walsh valid_dict(person_record, valid_values=valid_values) 58153902dd1SMichael Walsh valid_dict(person_record, invalid_values=invalid_values) 5827ac5fd81SMichael Walsh 583018e25fbSMichael Walsh Description of argument(s): 584018e25fbSMichael Walsh var_value The value being validated. 585da20f845SMichael Walsh required_keys A list of keys which must be found in the dictionary for it to be 586da20f845SMichael Walsh considered valid. 58753902dd1SMichael Walsh valid_values A dictionary whose entries correspond to the entries in var_value. Each 5888206851aSGeorge Keishing value in valid_values is itself a valid_values list for the corresponding 58953902dd1SMichael Walsh value in var_value. For any var_value[key] to be considered valid, its 59053902dd1SMichael Walsh value must be found in valid_values[key]. 59153902dd1SMichael Walsh 59253902dd1SMichael Walsh invalid_values A dictionary whose entries correspond to the entries in var_value. Each 59353902dd1SMichael Walsh value in invalid_values is itself an invalid_values list for the 594*81384420SMichael Walsh corresponding value in var_value. For any var_value[key] to be 595*81384420SMichael Walsh considered valid, its value must NOT be found in invalid_values[key]. 5967ac5fd81SMichael Walsh """ 5977ac5fd81SMichael Walsh 5987ac5fd81SMichael Walsh error_message = "" 599018e25fbSMichael Walsh missing_keys = list(set(required_keys) - set(var_value.keys())) 600018e25fbSMichael Walsh if len(missing_keys) > 0: 60189eff544SMichael Walsh var_name = get_var_name(var_name) 602018e25fbSMichael Walsh error_message += "The following dictionary is invalid because it is" 603018e25fbSMichael Walsh error_message += " missing required keys:\n" 60453902dd1SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank() | gp.show_type()) 605018e25fbSMichael Walsh error_message += "\n" 60635026be5SMichael Walsh error_message += gp.sprint_var(missing_keys, gp.show_type()) 6077ac5fd81SMichael Walsh return process_error_message(error_message) 608018e25fbSMichael Walsh 60953902dd1SMichael Walsh var_name = get_var_name(var_name) 61053902dd1SMichael Walsh if len(valid_values): 61153902dd1SMichael Walsh keys = valid_values.keys() 61253902dd1SMichael Walsh error_message = valid_dict(var_value, required_keys=keys, var_name=var_name) 61353902dd1SMichael Walsh if error_message: 61453902dd1SMichael Walsh return process_error_message(error_message) 61553902dd1SMichael Walsh for key, value in valid_values.items(): 61653902dd1SMichael Walsh key_name = " [" + key + "]" 61753902dd1SMichael Walsh sub_error_message = valid_value(var_value[key], valid_values=value, var_name=key_name) 61853902dd1SMichael Walsh if sub_error_message: 61953902dd1SMichael Walsh error_message += "The following dictionary is invalid because one of its entries is invalid:\n" 62053902dd1SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank() | gp.show_type()) 62153902dd1SMichael Walsh error_message += "\n" 62253902dd1SMichael Walsh error_message += sub_error_message 62353902dd1SMichael Walsh return process_error_message(error_message) 62453902dd1SMichael Walsh 62553902dd1SMichael Walsh for key, value in invalid_values.items(): 62653902dd1SMichael Walsh if key not in var_value: 62753902dd1SMichael Walsh continue 62853902dd1SMichael Walsh key_name = " [" + key + "]" 62953902dd1SMichael Walsh sub_error_message = valid_value(var_value[key], invalid_values=value, var_name=key_name) 63053902dd1SMichael Walsh if sub_error_message: 63153902dd1SMichael Walsh error_message += "The following dictionary is invalid because one of its entries is invalid:\n" 63253902dd1SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank() | gp.show_type()) 63353902dd1SMichael Walsh error_message += "\n" 63453902dd1SMichael Walsh error_message += sub_error_message 63553902dd1SMichael Walsh return process_error_message(error_message) 63653902dd1SMichael Walsh 63753902dd1SMichael Walsh return process_error_message(error_message) 63853902dd1SMichael Walsh 639018e25fbSMichael Walsh 64089eff544SMichael Walshdef valid_program(var_value, var_name=None): 641be3a8150SMichael Walsh r""" 642da20f845SMichael Walsh The variable value is valid if it contains the name of a program which can be located using the "which" 643da20f845SMichael Walsh command. 644be3a8150SMichael Walsh 645be3a8150SMichael Walsh Description of argument(s): 646be3a8150SMichael Walsh var_value The value being validated. 647be3a8150SMichael Walsh """ 648be3a8150SMichael Walsh 649be3a8150SMichael Walsh error_message = "" 650be3a8150SMichael Walsh rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0, 651be3a8150SMichael Walsh ignore_err=1) 652be3a8150SMichael Walsh if rc: 65389eff544SMichael Walsh var_name = get_var_name(var_name) 654be3a8150SMichael Walsh error_message += "The following required program could not be found" 655be3a8150SMichael Walsh error_message += " using the $PATH environment variable:\n" 65600244345SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 657be3a8150SMichael Walsh PATH = os.environ.get("PATH", "").split(":") 658be3a8150SMichael Walsh error_message += "\n" 659be3a8150SMichael Walsh error_message += gp.sprint_var(PATH) 660be3a8150SMichael Walsh return process_error_message(error_message) 661be3a8150SMichael Walsh 662be3a8150SMichael Walsh 66389eff544SMichael Walshdef valid_length(var_value, min_length=None, max_length=None, var_name=None): 664b9d8dfd2SMichael Walsh r""" 665da20f845SMichael Walsh The variable value is valid if it is an object (e.g. list, dictionary) whose length is within the 666da20f845SMichael Walsh specified range. 667b9d8dfd2SMichael Walsh 668b9d8dfd2SMichael Walsh Description of argument(s): 669b9d8dfd2SMichael Walsh var_value The value being validated. 670da20f845SMichael Walsh min_length The minimum length of the object. If not None, the length of var_value 671da20f845SMichael Walsh must be greater than or equal to min_length. 672da20f845SMichael Walsh max_length The maximum length of the object. If not None, the length of var_value 673da20f845SMichael Walsh must be less than or equal to min_length. 674b9d8dfd2SMichael Walsh """ 675b9d8dfd2SMichael Walsh 676b9d8dfd2SMichael Walsh error_message = "" 677b9d8dfd2SMichael Walsh length = len(var_value) 678b9d8dfd2SMichael Walsh error_message = valid_range(length, min_length, max_length) 679b9d8dfd2SMichael Walsh if error_message: 68089eff544SMichael Walsh var_name = get_var_name(var_name) 681b9d8dfd2SMichael Walsh error_message = "The length of the following object is not within the" 682b9d8dfd2SMichael Walsh error_message += " expected range:\n" 683da20f845SMichael Walsh error_message += gp.sprint_vars(min_length, max_length) 684b9d8dfd2SMichael Walsh error_message += gp.sprint_var(length) 685b9d8dfd2SMichael Walsh error_message += gp.sprint_varx(var_name, var_value, gp.blank()) 686b9d8dfd2SMichael Walsh error_message += "\n" 687b9d8dfd2SMichael Walsh return process_error_message(error_message) 688b9d8dfd2SMichael Walsh 689b9d8dfd2SMichael Walsh return process_error_message(error_message) 690b9d8dfd2SMichael Walsh 691b9d8dfd2SMichael Walsh 692018e25fbSMichael Walsh# Modify selected function docstrings by adding headers/footers. 693018e25fbSMichael Walsh 694018e25fbSMichael Walshfunc_names = [ 695018e25fbSMichael Walsh "valid_type", "valid_value", "valid_range", "valid_integer", 696018e25fbSMichael Walsh "valid_dir_path", "valid_file_path", "valid_path", "valid_list", 6978333a18dSMichael Walsh "valid_dict", "valid_program", "valid_length", "valid_float", 6988333a18dSMichael Walsh "valid_date_time" 699018e25fbSMichael Walsh] 700018e25fbSMichael Walsh 701018e25fbSMichael Walshraw_doc_strings = {} 702018e25fbSMichael Walsh 703018e25fbSMichael Walshfor func_name in func_names: 704018e25fbSMichael Walsh cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name 705018e25fbSMichael Walsh cmd_buf += ".__doc__" 706018e25fbSMichael Walsh exec(cmd_buf) 707018e25fbSMichael Walsh cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name 708018e25fbSMichael Walsh cmd_buf += ".__doc__.rstrip(\" \\n\") + additional_args_docstring_footer" 709018e25fbSMichael Walsh exec(cmd_buf) 710