| #!/usr/bin/env python3 | 
 |  | 
 | r""" | 
 | This module provides validation functions like valid_value(), valid_integer(), etc. | 
 | """ | 
 |  | 
 | import datetime | 
 | import os | 
 |  | 
 | import func_args as fa | 
 | import gen_cmd as gc | 
 | import gen_print as gp | 
 |  | 
 | exit_on_error = False | 
 |  | 
 |  | 
 | def set_exit_on_error(value): | 
 |     r""" | 
 |     Set the exit_on_error value to either True or False. | 
 |  | 
 |     If exit_on_error is set, validation functions like valid_value() will exit the program on error instead | 
 |     of returning False. | 
 |  | 
 |     Description of argument(s): | 
 |     value                           Value to set global exit_on_error to. | 
 |     """ | 
 |  | 
 |     global exit_on_error | 
 |     exit_on_error = value | 
 |  | 
 |  | 
 | def get_var_name(var_name): | 
 |     r""" | 
 |     If var_name is not None, simply return its value.  Otherwise, get the variable name of the first argument | 
 |     used to call the validation function (e.g. valid, valid_integer, etc.) and return it. | 
 |  | 
 |     This function is designed solely for use by other functions in this file. | 
 |  | 
 |     Example: | 
 |  | 
 |     A programmer codes this: | 
 |  | 
 |     valid_value(last_name) | 
 |  | 
 |     Which results in the following call stack: | 
 |  | 
 |     valid_value(last_name) | 
 |       -> get_var_name(var_name) | 
 |  | 
 |     In this example, this function will return "last_name". | 
 |  | 
 |     Example: | 
 |  | 
 |     err_msg = valid_value(last_name, var_name="some_other_name") | 
 |  | 
 |     Which results in the following call stack: | 
 |  | 
 |     valid_value(var_value, var_name="some_other_name") | 
 |       -> get_var_name(var_name) | 
 |  | 
 |     In this example, this function will return "some_other_name". | 
 |  | 
 |     Description of argument(s): | 
 |     var_name                        The name of the variable. | 
 |     """ | 
 |  | 
 |     return var_name or gp.get_arg_name(0, 1, stack_frame_ix=3) | 
 |  | 
 |  | 
 | def process_error_message(error_message): | 
 |     r""" | 
 |     Process the error_message in the manner described below. | 
 |  | 
 |     This function is designed solely for use by other functions in this file. | 
 |  | 
 |     NOTE: A blank error_message means that there is no error. | 
 |  | 
 |     For the following explanations, assume the caller of this function is a function with the following | 
 |     definition: | 
 |     valid_value(var_value, valid_values=[], invalid_values=[], var_name=None): | 
 |  | 
 |     If the user of valid_value() is assigning the valid_value() return value to a variable, | 
 |     process_error_message() will simply return the error_message.  This mode of usage is illustrated by the | 
 |     following example: | 
 |  | 
 |     error_message = valid_value(var1) | 
 |  | 
 |     This mode is useful for callers who wish to validate a variable and then decide for themselves what to do | 
 |     with the error_message (e.g. raise(error_message), BuiltIn().fail(error_message), etc.). | 
 |  | 
 |     If the user of valid_value() is NOT assigning the valid_value() return value to a variable, | 
 |     process_error_message() will behave as follows. | 
 |  | 
 |     First, if error_message is non-blank, it will be printed to stderr via a call to | 
 |     gp.print_error_report(error_message). | 
 |  | 
 |     If exit_on_error is set: | 
 |     - If the error_message is blank, simply return. | 
 |     - If the error_message is non-blank, exit the program with a return code of 1. | 
 |  | 
 |     If exit_on_error is NOT set: | 
 |     - If the error_message is blank, return True. | 
 |     - If the error_message is non-blank, return False. | 
 |  | 
 |     Description of argument(s): | 
 |     error_message                   An error message. | 
 |     """ | 
 |  | 
 |     # Determine whether the caller's caller is assigning the result to a variable. | 
 |     l_value = gp.get_arg_name(None, -1, stack_frame_ix=3) | 
 |     if l_value: | 
 |         return error_message | 
 |  | 
 |     if error_message == "": | 
 |         if exit_on_error: | 
 |             return | 
 |         return True | 
 |  | 
 |     gp.print_error_report(error_message, stack_frame_ix=4) | 
 |     if exit_on_error: | 
 |         exit(1) | 
 |     return False | 
 |  | 
 |  | 
 | # Note to programmers:  All of the validation functions in this module should follow the same basic template: | 
 | # def valid_value(var_value, var1, var2, varn, var_name=None): | 
 | # | 
 | #     error_message = "" | 
 | #     if not valid: | 
 | #         var_name = get_var_name(var_name) | 
 | #         error_message += "The following variable is invalid because...:\n" | 
 | #         error_message += gp.sprint_varx(var_name, var_value, gp.blank()) | 
 | # | 
 | #     return process_error_message(error_message) | 
 |  | 
 |  | 
 | # The docstring header and footer will be added to each validation function's existing docstring. | 
 | docstring_header = r""" | 
 |     Determine whether var_value is valid, construct an error_message and call | 
 |     process_error_message(error_message). | 
 |  | 
 |     See the process_error_message() function defined in this module for a description of how error messages | 
 |     are processed. | 
 |     """ | 
 |  | 
 | additional_args_docstring_footer = r""" | 
 |     var_name                        The name of the variable whose value is passed in var_value.  For the | 
 |                                     general case, this argument is unnecessary as this function can figure | 
 |                                     out the var_name.  This is provided for Robot callers in which case, this | 
 |                                     function lacks the ability to determine the variable name. | 
 |     """ | 
 |  | 
 |  | 
 | def valid_type(var_value, required_type, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it is of the required type. | 
 |  | 
 |     Examples: | 
 |  | 
 |     valid_type(var1, int) | 
 |  | 
 |     valid_type(var1, (list, dict)) | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     required_type                   A type or a tuple of types (e.g. str, int, etc.). | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     if type(required_type) is tuple: | 
 |         if type(var_value) in required_type: | 
 |             return process_error_message(error_message) | 
 |     else: | 
 |         if type(var_value) is required_type: | 
 |             return process_error_message(error_message) | 
 |  | 
 |     # If we get to this point, the validation has failed. | 
 |     var_name = get_var_name(var_name) | 
 |     error_message += "Invalid variable type:\n" | 
 |     error_message += gp.sprint_varx( | 
 |         var_name, var_value, gp.blank() | gp.show_type() | 
 |     ) | 
 |     error_message += "\n" | 
 |     error_message += gp.sprint_var(required_type) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_value(var_value, valid_values=[], invalid_values=[], var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it is either contained in the valid_values list or if it is NOT contained | 
 |     in the invalid_values list.  If the caller specifies nothing for either of these 2 arguments, | 
 |     invalid_values will be initialized to ['', None].  This is a good way to fail on variables which contain | 
 |     blank values. | 
 |  | 
 |     It is illegal to specify both valid_values and invalid values. | 
 |  | 
 |     Example: | 
 |  | 
 |     var1 = '' | 
 |     valid_value(var1) | 
 |  | 
 |     This code would fail because var1 is blank and the default value for invalid_values is ['', None]. | 
 |  | 
 |     Example: | 
 |     var1 = 'yes' | 
 |     valid_value(var1, valid_values=['yes', 'true']) | 
 |  | 
 |     This code would pass. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     valid_values                    A list of valid values.  The variable value must be equal to one of these | 
 |                                     values to be considered valid. | 
 |     invalid_values                  A list of invalid values.  If the variable value is equal to any of | 
 |                                     these, it is considered invalid. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |  | 
 |     # Validate this function's arguments. | 
 |     len_valid_values = len(valid_values) | 
 |     len_invalid_values = len(invalid_values) | 
 |     if len_valid_values > 0 and len_invalid_values > 0: | 
 |         error_message += "Programmer error - You must provide either an" | 
 |         error_message += " invalid_values list or a valid_values" | 
 |         error_message += " list but NOT both:\n" | 
 |         error_message += gp.sprint_var(invalid_values) | 
 |         error_message += gp.sprint_var(valid_values) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     error_message = valid_type(valid_values, list, var_name="valid_values") | 
 |     if error_message: | 
 |         return process_error_message(error_message) | 
 |  | 
 |     error_message = valid_type(invalid_values, list, var_name="invalid_values") | 
 |     if error_message: | 
 |         return process_error_message(error_message) | 
 |  | 
 |     if len_valid_values > 0: | 
 |         # Processing the valid_values list. | 
 |         if var_value in valid_values: | 
 |             return process_error_message(error_message) | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "Invalid variable value:\n" | 
 |         error_message += gp.sprint_varx( | 
 |             var_name, var_value, gp.blank() | gp.verbose() | gp.show_type() | 
 |         ) | 
 |         error_message += "\n" | 
 |         error_message += "It must be one of the following values:\n" | 
 |         error_message += "\n" | 
 |         error_message += gp.sprint_var( | 
 |             valid_values, gp.blank() | gp.show_type() | 
 |         ) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     if len_invalid_values == 0: | 
 |         # Assign default value. | 
 |         invalid_values = ["", None] | 
 |  | 
 |     # Assertion: We have an invalid_values list.  Processing it now. | 
 |     if var_value not in invalid_values: | 
 |         return process_error_message(error_message) | 
 |  | 
 |     var_name = get_var_name(var_name) | 
 |     error_message += "Invalid variable value:\n" | 
 |     error_message += gp.sprint_varx( | 
 |         var_name, var_value, gp.blank() | gp.verbose() | gp.show_type() | 
 |     ) | 
 |     error_message += "\n" | 
 |     error_message += "It must NOT be any of the following values:\n" | 
 |     error_message += "\n" | 
 |     error_message += gp.sprint_var(invalid_values, gp.blank() | gp.show_type()) | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_range(var_value, lower=None, upper=None, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it is within the specified range. | 
 |  | 
 |     This function can be used with any type of operands where they can have a greater than/less than | 
 |     relationship to each other (e.g. int, float, str). | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     lower                           The lower end of the range.  If not None, the var_value must be greater | 
 |                                     than or equal to lower. | 
 |     upper                           The upper end of the range.  If not None, the var_value must be less than | 
 |                                     or equal to upper. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     if lower is None and upper is None: | 
 |         return process_error_message(error_message) | 
 |     if lower is None and var_value <= upper: | 
 |         return process_error_message(error_message) | 
 |     if upper is None and var_value >= lower: | 
 |         return process_error_message(error_message) | 
 |     if lower is not None and upper is not None: | 
 |         if lower > upper: | 
 |             var_name = get_var_name(var_name) | 
 |             error_message += "Programmer error - the lower value is greater" | 
 |             error_message += " than the upper value:\n" | 
 |             error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type()) | 
 |             return process_error_message(error_message) | 
 |         if lower <= var_value <= upper: | 
 |             return process_error_message(error_message) | 
 |  | 
 |     var_name = get_var_name(var_name) | 
 |     error_message += "The following variable is not within the expected" | 
 |     error_message += " range:\n" | 
 |     error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) | 
 |     error_message += "\n" | 
 |     error_message += "range:\n" | 
 |     error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2) | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_integer(var_value, lower=None, upper=None, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it is an integer or can be interpreted as an integer (e.g. 7, "7", etc.). | 
 |  | 
 |     This function also calls valid_range to make sure the integer value is within the specified range (if | 
 |     any). | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     lower                           The lower end of the range.  If not None, the var_value must be greater | 
 |                                     than or equal to lower. | 
 |     upper                           The upper end of the range.  If not None, the var_value must be less than | 
 |                                     or equal to upper. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     var_name = get_var_name(var_name) | 
 |     try: | 
 |         var_value = int(str(var_value), 0) | 
 |     except ValueError: | 
 |         error_message += "Invalid integer value:\n" | 
 |         error_message += gp.sprint_varx( | 
 |             var_name, var_value, gp.blank() | gp.show_type() | 
 |         ) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     # Check the range (if any). | 
 |     if lower: | 
 |         lower = int(str(lower), 0) | 
 |     if upper: | 
 |         upper = int(str(upper), 0) | 
 |     error_message = valid_range(var_value, lower, upper, var_name=var_name) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_float(var_value, lower=None, upper=None, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it is a floating point value or can be interpreted as a floating point | 
 |     value (e.g. 7.5, "7.5", etc.). | 
 |  | 
 |     This function also calls valid_range to make sure the float value is within the specified range (if any). | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     lower                           The lower end of the range.  If not None, the var_value must be greater | 
 |                                     than or equal to lower. | 
 |     upper                           The upper end of the range.  If not None, the var_value must be less than | 
 |                                     or equal to upper. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     var_name = get_var_name(var_name) | 
 |     try: | 
 |         var_value = float(str(var_value)) | 
 |     except ValueError: | 
 |         error_message += "Invalid float value:\n" | 
 |         error_message += gp.sprint_varx( | 
 |             var_name, var_value, gp.blank() | gp.show_type() | 
 |         ) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     # Check the range (if any). | 
 |     if lower: | 
 |         lower = float(str(lower)) | 
 |     if upper: | 
 |         upper = float(str(upper)) | 
 |     error_message = valid_range(var_value, lower, upper, var_name=var_name) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_date_time(var_value, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it can be interpreted as a date/time (e.g. "14:49:49.981", "tomorrow", | 
 |     etc.) by the linux date command. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     rc, out_buf = gc.shell_cmd( | 
 |         "date -d '" + str(var_value) + "'", quiet=1, show_err=0, ignore_err=1 | 
 |     ) | 
 |     if rc: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "Invalid date/time value:\n" | 
 |         error_message += gp.sprint_varx( | 
 |             var_name, var_value, gp.blank() | gp.show_type() | 
 |         ) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_dir_path(var_value, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it contains the path of an existing directory. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     if not os.path.isdir(str(var_value)): | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "The following directory does not exist:\n" | 
 |         error_message += gp.sprint_varx(var_name, var_value, gp.blank()) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_file_path(var_value, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it contains the path of an existing file. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     if not os.path.isfile(str(var_value)): | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "The following file does not exist:\n" | 
 |         error_message += gp.sprint_varx(var_name, var_value, gp.blank()) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_path(var_value, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it contains the path of an existing file or directory. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))): | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "Invalid path (file or directory does not exist):\n" | 
 |         error_message += gp.sprint_varx(var_name, var_value, gp.blank()) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_list( | 
 |     var_value, | 
 |     valid_values=[], | 
 |     invalid_values=[], | 
 |     required_values=[], | 
 |     fail_on_empty=False, | 
 |     var_name=None, | 
 | ): | 
 |     r""" | 
 |     The variable value is valid if it is a list where each entry can be found in the valid_values list or if | 
 |     none of its values can be found in the invalid_values list or if all of the values in the required_values | 
 |     list can be found in var_value. | 
 |  | 
 |     The caller may only specify one of these 3 arguments: valid_values, invalid_values, required_values. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     valid_values                    A list of valid values.  Each element in the var_value list must be equal | 
 |                                     to one of these values to be considered valid. | 
 |     invalid_values                  A list of invalid values.  If any element in var_value is equal to any of | 
 |                                     the values in this argument, var_value is considered invalid. | 
 |     required_values                 Every value in required_values must be found in var_value.  Otherwise, | 
 |                                     var_value is considered invalid. | 
 |     fail_on_empty                   Indicates that an empty list for the variable value should be considered | 
 |                                     an error. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |  | 
 |     # Validate this function's arguments. | 
 |     if not ( | 
 |         bool(len(valid_values)) | 
 |         ^ bool(len(invalid_values)) | 
 |         ^ bool(len(required_values)) | 
 |     ): | 
 |         error_message += "Programmer error - You must provide only one of the" | 
 |         error_message += " following: valid_values, invalid_values," | 
 |         error_message += " required_values.\n" | 
 |         error_message += gp.sprint_var(invalid_values, gp.show_type()) | 
 |         error_message += gp.sprint_var(valid_values, gp.show_type()) | 
 |         error_message += gp.sprint_var(required_values, gp.show_type()) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     if type(var_value) is not list: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message = valid_type(var_value, list, var_name=var_name) | 
 |         if error_message: | 
 |             return process_error_message(error_message) | 
 |  | 
 |     if fail_on_empty and len(var_value) == 0: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "Invalid empty list:\n" | 
 |         error_message += gp.sprint_varx(var_name, var_value, gp.show_type()) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     if len(required_values): | 
 |         found_error = 0 | 
 |         display_required_values = list(required_values) | 
 |         for ix in range(0, len(required_values)): | 
 |             if required_values[ix] not in var_value: | 
 |                 found_error = 1 | 
 |                 display_required_values[ix] = ( | 
 |                     str(display_required_values[ix]) + "*" | 
 |                 ) | 
 |         if found_error: | 
 |             var_name = get_var_name(var_name) | 
 |             error_message += "The following list is invalid:\n" | 
 |             error_message += gp.sprint_varx( | 
 |                 var_name, var_value, gp.blank() | gp.show_type() | 
 |             ) | 
 |             error_message += "\n" | 
 |             error_message += "Because some of the values in the " | 
 |             error_message += "required_values list are not present (see" | 
 |             error_message += ' entries marked with "*"):\n' | 
 |             error_message += "\n" | 
 |             error_message += gp.sprint_varx( | 
 |                 "required_values", | 
 |                 display_required_values, | 
 |                 gp.blank() | gp.show_type(), | 
 |             ) | 
 |             error_message += "\n" | 
 |  | 
 |         return process_error_message(error_message) | 
 |  | 
 |     if len(invalid_values): | 
 |         found_error = 0 | 
 |         display_var_value = list(var_value) | 
 |         for ix in range(0, len(var_value)): | 
 |             if var_value[ix] in invalid_values: | 
 |                 found_error = 1 | 
 |                 display_var_value[ix] = str(var_value[ix]) + "*" | 
 |  | 
 |         if found_error: | 
 |             var_name = get_var_name(var_name) | 
 |             error_message += "The following list is invalid (see entries" | 
 |             error_message += ' marked with "*"):\n' | 
 |             error_message += gp.sprint_varx( | 
 |                 var_name, display_var_value, gp.blank() | gp.show_type() | 
 |             ) | 
 |             error_message += "\n" | 
 |             error_message += gp.sprint_var(invalid_values, gp.show_type()) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     found_error = 0 | 
 |     display_var_value = list(var_value) | 
 |     for ix in range(0, len(var_value)): | 
 |         if var_value[ix] not in valid_values: | 
 |             found_error = 1 | 
 |             display_var_value[ix] = str(var_value[ix]) + "*" | 
 |  | 
 |     if found_error: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "The following list is invalid (see entries marked" | 
 |         error_message += ' with "*"):\n' | 
 |         error_message += gp.sprint_varx( | 
 |             var_name, display_var_value, gp.blank() | gp.show_type() | 
 |         ) | 
 |         error_message += "\n" | 
 |         error_message += gp.sprint_var(valid_values, gp.show_type()) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_dict( | 
 |     var_value, | 
 |     required_keys=[], | 
 |     valid_values={}, | 
 |     invalid_values={}, | 
 |     var_name=None, | 
 | ): | 
 |     r""" | 
 |     The dictionary variable value is valid if it contains all required keys and each entry passes the | 
 |     valid_value() call. | 
 |  | 
 |     Examples: | 
 |     person_record = {'last_name': 'Jones', 'first_name': 'John'} | 
 |     valid_values = {'last_name': ['Doe', 'Jones', 'Johnson'], 'first_name': ['John', 'Mary']} | 
 |     invalid_values = {'last_name': ['Manson', 'Hitler', 'Presley'], 'first_name': ['Mickey', 'Goofy']} | 
 |  | 
 |     valid_dict(person_record, valid_values=valid_values) | 
 |     valid_dict(person_record, invalid_values=invalid_values) | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     required_keys                   A list of keys which must be found in the dictionary for it to be | 
 |                                     considered valid. | 
 |     valid_values                    A dictionary whose entries correspond to the entries in var_value.  Each | 
 |                                     value in valid_values is itself a valid_values list for the corresponding | 
 |                                     value in var_value.  For any var_value[key] to be considered valid, its | 
 |                                     value must be found in valid_values[key]. | 
 |  | 
 |     invalid_values                  A dictionary whose entries correspond to the entries in var_value.  Each | 
 |                                     value in invalid_values is itself an invalid_values list for the | 
 |                                     corresponding value in var_value.  For any var_value[key] to be | 
 |                                     considered valid, its value must NOT be found in invalid_values[key]. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     missing_keys = list(set(required_keys) - set(var_value.keys())) | 
 |     if len(missing_keys) > 0: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "The following dictionary is invalid because it is" | 
 |         error_message += " missing required keys:\n" | 
 |         error_message += gp.sprint_varx( | 
 |             var_name, var_value, gp.blank() | gp.show_type() | 
 |         ) | 
 |         error_message += "\n" | 
 |         error_message += gp.sprint_var(missing_keys, gp.show_type()) | 
 |         return process_error_message(error_message) | 
 |  | 
 |     var_name = get_var_name(var_name) | 
 |     if len(valid_values): | 
 |         keys = valid_values.keys() | 
 |         error_message = valid_dict( | 
 |             var_value, required_keys=keys, var_name=var_name | 
 |         ) | 
 |         if error_message: | 
 |             return process_error_message(error_message) | 
 |     for key, value in valid_values.items(): | 
 |         key_name = "  [" + key + "]" | 
 |         sub_error_message = valid_value( | 
 |             var_value[key], valid_values=value, var_name=key_name | 
 |         ) | 
 |         if sub_error_message: | 
 |             error_message += ( | 
 |                 "The following dictionary is invalid because one of its" | 
 |                 " entries is invalid:\n" | 
 |             ) | 
 |             error_message += gp.sprint_varx( | 
 |                 var_name, var_value, gp.blank() | gp.show_type() | 
 |             ) | 
 |             error_message += "\n" | 
 |             error_message += sub_error_message | 
 |             return process_error_message(error_message) | 
 |  | 
 |     for key, value in invalid_values.items(): | 
 |         if key not in var_value: | 
 |             continue | 
 |         key_name = "  [" + key + "]" | 
 |         sub_error_message = valid_value( | 
 |             var_value[key], invalid_values=value, var_name=key_name | 
 |         ) | 
 |         if sub_error_message: | 
 |             error_message += ( | 
 |                 "The following dictionary is invalid because one of its" | 
 |                 " entries is invalid:\n" | 
 |             ) | 
 |             error_message += gp.sprint_varx( | 
 |                 var_name, var_value, gp.blank() | gp.show_type() | 
 |             ) | 
 |             error_message += "\n" | 
 |             error_message += sub_error_message | 
 |             return process_error_message(error_message) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_program(var_value, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it contains the name of a program which can be located using the "which" | 
 |     command. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     rc, out_buf = gc.shell_cmd( | 
 |         "which " + var_value, quiet=1, show_err=0, ignore_err=1 | 
 |     ) | 
 |     if rc: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message += "The following required program could not be found" | 
 |         error_message += " using the $PATH environment variable:\n" | 
 |         error_message += gp.sprint_varx(var_name, var_value, gp.blank()) | 
 |         PATH = os.environ.get("PATH", "").split(":") | 
 |         error_message += "\n" | 
 |         error_message += gp.sprint_var(PATH) | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | def valid_length(var_value, min_length=None, max_length=None, var_name=None): | 
 |     r""" | 
 |     The variable value is valid if it is an object (e.g. list, dictionary) whose length is within the | 
 |     specified range. | 
 |  | 
 |     Description of argument(s): | 
 |     var_value                       The value being validated. | 
 |     min_length                      The minimum length of the object.  If not None, the length of var_value | 
 |                                     must be greater than or equal to min_length. | 
 |     max_length                      The maximum length of the object.  If not None, the length of var_value | 
 |                                     must be less than or equal to min_length. | 
 |     """ | 
 |  | 
 |     error_message = "" | 
 |     length = len(var_value) | 
 |     error_message = valid_range(length, min_length, max_length) | 
 |     if error_message: | 
 |         var_name = get_var_name(var_name) | 
 |         error_message = "The length of the following object is not within the" | 
 |         error_message += " expected range:\n" | 
 |         error_message += gp.sprint_vars(min_length, max_length) | 
 |         error_message += gp.sprint_var(length) | 
 |         error_message += gp.sprint_varx(var_name, var_value, gp.blank()) | 
 |         error_message += "\n" | 
 |         return process_error_message(error_message) | 
 |  | 
 |     return process_error_message(error_message) | 
 |  | 
 |  | 
 | # Modify selected function docstrings by adding headers/footers. | 
 |  | 
 | func_names = [ | 
 |     "valid_type", | 
 |     "valid_value", | 
 |     "valid_range", | 
 |     "valid_integer", | 
 |     "valid_dir_path", | 
 |     "valid_file_path", | 
 |     "valid_path", | 
 |     "valid_list", | 
 |     "valid_dict", | 
 |     "valid_program", | 
 |     "valid_length", | 
 |     "valid_float", | 
 |     "valid_date_time", | 
 | ] | 
 |  | 
 | raw_doc_strings = {} | 
 |  | 
 | for func_name in func_names: | 
 |     cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name | 
 |     cmd_buf += ".__doc__" | 
 |     exec(cmd_buf) | 
 |     cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name | 
 |     cmd_buf += '.__doc__.rstrip(" \\n") + additional_args_docstring_footer' | 
 |     exec(cmd_buf) |