| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python | 
|  | 2 |  | 
|  | 3 | r""" | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 4 | This module provides validation functions like valid_value(), valid_integer(), | 
|  | 5 | etc. for robot programs. | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 6 | """ | 
|  | 7 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 8 | import re | 
| Michael Walsh | c108e42 | 2019-03-28 12:27:18 -0500 | [diff] [blame] | 9 | import gen_print as gp | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 10 | import gen_valid as gv | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 11 | import func_args as fa | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 12 |  | 
|  | 13 | from robot.libraries.BuiltIn import BuiltIn | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 14 |  | 
|  | 15 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 16 | def valid_var_name(var_name): | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 17 | r""" | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 18 | Validate the robot variable name and return its value. | 
| Michael Walsh | 3e26e10 | 2017-01-10 11:29:28 -0600 | [diff] [blame] | 19 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 20 | If the variable is undefined, this function will print an error message | 
|  | 21 | and call BuiltIn().fail(). | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 22 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 23 | Description of arguments(): | 
|  | 24 | var_name                        The name of the robot variable (e.g. | 
|  | 25 | "var1").  Do not include "${}" (e.g. | 
|  | 26 | "${var1}".  Just provide the simple name | 
|  | 27 | of the variable. | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 28 | """ | 
|  | 29 |  | 
|  | 30 | # Note: get_variable_value() seems to have no trouble with local variables. | 
|  | 31 | var_value = BuiltIn().get_variable_value("${" + var_name + "}") | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 32 | if var_value is None: | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 33 | var_value = "<undefined>" | 
|  | 34 | error_message = gv.valid_value(var_value, invalid_values=[var_value], | 
|  | 35 | var_name=var_name) | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 36 | BuiltIn().fail(error_message) | 
|  | 37 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 38 | return var_value | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 39 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 40 |  | 
|  | 41 | def valid_init(var_name, *args, **kwargs): | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 42 | r""" | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 43 | Do initialization for variable validation and return var_name, args and | 
|  | 44 | kwargs. | 
| Michael Walsh | 3e26e10 | 2017-01-10 11:29:28 -0600 | [diff] [blame] | 45 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 46 | This function is to be called by all of the various validation functions | 
|  | 47 | in this module. | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 48 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 49 | This function is designed solely for use by other functions in this file. | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 50 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 51 | Description of argument(s): | 
|  | 52 | var_name                        The name of the variable to be validated. | 
|  | 53 | args                            The positional arguments to be passed to a | 
|  | 54 | validation function. | 
|  | 55 | kwargs                          The keyword arguments to be passed to a | 
|  | 56 | validation function. | 
| Michael Walsh | 1817632 | 2016-11-15 15:11:21 -0600 | [diff] [blame] | 57 | """ | 
|  | 58 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 59 | var_value = valid_var_name(var_name) | 
|  | 60 | # Convert python string object definitions to objects (useful for robot | 
|  | 61 | # callers). | 
|  | 62 | args = fa.args_to_objects(args) | 
|  | 63 | kwargs = fa.args_to_objects(kwargs) | 
|  | 64 | return var_value, args, kwargs | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 65 |  | 
|  | 66 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 67 | def process_error_message(error_message): | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 68 | r""" | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 69 | Process an error message. | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 70 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 71 | If error_message is non-blank, fail.  Otherwise, do nothing. | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 72 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 73 | This function is designed solely for use by other functions in this file. | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 74 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 75 | Description of argument(s): | 
|  | 76 | error_message                   The error message to be processed. | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 77 | """ | 
|  | 78 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 79 | if error_message: | 
| Michael Walsh | c108e42 | 2019-03-28 12:27:18 -0500 | [diff] [blame] | 80 | error_message = gp.sprint_error_report(error_message) | 
| Michael Walsh | 2c687e9 | 2018-05-09 11:47:56 -0500 | [diff] [blame] | 81 | BuiltIn().fail(error_message) | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 82 |  | 
|  | 83 |  | 
|  | 84 | # The docstring header will be pre-pended to each validation function's | 
|  | 85 | # existing docstring. | 
|  | 86 | docstring_header = \ | 
|  | 87 | r""" | 
|  | 88 | Fail if the variable named by var_name is invalid. | 
|  | 89 | """ | 
|  | 90 |  | 
|  | 91 |  | 
|  | 92 | def customize_doc_string(doc_string): | 
|  | 93 | r""" | 
|  | 94 | Customize a gen_valid function docstring and return the result. | 
|  | 95 |  | 
|  | 96 | This function is designed solely for use by other functions in this file. | 
|  | 97 |  | 
|  | 98 | The caller should pass a docstring from a gen_valid.py validation | 
|  | 99 | function.  This docstring will be changed to make a suitable docstring for | 
|  | 100 | this module's corresponding validation function. | 
|  | 101 |  | 
|  | 102 | For example: | 
|  | 103 |  | 
|  | 104 | Let's suppose that gen_valid.py has a function called "valid_value()". | 
|  | 105 | This module could make the following call to essentially copy gen_valid's | 
|  | 106 | "valid_value()" function, modify it and then assign it to the local | 
|  | 107 | version of the valid_value() function. | 
|  | 108 |  | 
|  | 109 | valid.__doc__ = customize_doc_string(gv.valid.__doc__) | 
|  | 110 |  | 
|  | 111 | Description of argument(s): | 
|  | 112 | doc_string                      The docstring to be customized. | 
|  | 113 | """ | 
|  | 114 |  | 
|  | 115 | doc_string = docstring_header + doc_string | 
|  | 116 | doc_string = doc_string.split("\n") | 
|  | 117 |  | 
|  | 118 | start_ix = 0 | 
|  | 119 | # Find the "var_value" line. | 
|  | 120 | start_ix = next((index for index, value in | 
|  | 121 | enumerate(doc_string[start_ix:], start_ix) | 
|  | 122 | if re.match("[ ]+var_value  ", value)), None) | 
|  | 123 | # Replace the "var_value" line with our "var_name" line. | 
|  | 124 | doc_string[start_ix] = "    var_name                        " \ | 
|  | 125 | + "The name of the variable to be validated." | 
|  | 126 |  | 
|  | 127 | return "\n".join(doc_string) | 
|  | 128 |  | 
|  | 129 |  | 
|  | 130 | # All of the following functions are robot wrappers for the equivalent | 
|  | 131 | # functions defined in gen_valid.py.  Note that the only difference between | 
|  | 132 | # any two of these locally defined functions is the function name and the | 
|  | 133 | # gv.<function name> which they call.  Also, note that the docstring for each | 
|  | 134 | # is created by modifying the docstring from the supporting gen_valid.py | 
|  | 135 | # function. | 
|  | 136 |  | 
|  | 137 | def valid_type(var_name, *args, **kwargs): | 
|  | 138 |  | 
|  | 139 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 140 | error_message = \ | 
|  | 141 | gv.valid_type(var_value, *args, var_name=var_name, **kwargs) | 
|  | 142 | process_error_message(error_message) | 
|  | 143 |  | 
|  | 144 |  | 
|  | 145 | def valid_value(var_name, *args, **kwargs): | 
|  | 146 |  | 
|  | 147 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 148 | error_message = \ | 
|  | 149 | gv.valid_value(var_value, *args, var_name=var_name, **kwargs) | 
|  | 150 | process_error_message(error_message) | 
|  | 151 |  | 
|  | 152 |  | 
|  | 153 | def valid_range(var_name, *args, **kwargs): | 
|  | 154 |  | 
|  | 155 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 156 | error_message = \ | 
|  | 157 | gv.valid_range(var_value, *args, var_name=var_name, **kwargs) | 
|  | 158 | process_error_message(error_message) | 
|  | 159 |  | 
|  | 160 |  | 
|  | 161 | def valid_integer(var_name, *args, **kwargs): | 
|  | 162 |  | 
|  | 163 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 164 | error_message = \ | 
|  | 165 | gv.valid_integer(var_value, *args, var_name=var_name, **kwargs) | 
|  | 166 | process_error_message(error_message) | 
|  | 167 |  | 
|  | 168 |  | 
|  | 169 | def valid_dir_path(var_name, *args, **kwargs): | 
|  | 170 |  | 
|  | 171 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 172 | error_message = \ | 
|  | 173 | gv.valid_dir_path(var_value, *args, var_name=var_name, **kwargs) | 
|  | 174 | process_error_message(error_message) | 
|  | 175 |  | 
|  | 176 |  | 
|  | 177 | def valid_file_path(var_name, *args, **kwargs): | 
|  | 178 |  | 
|  | 179 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 180 | error_message = \ | 
|  | 181 | gv.valid_file_path(var_value, *args, var_name=var_name, **kwargs) | 
|  | 182 | process_error_message(error_message) | 
|  | 183 |  | 
|  | 184 |  | 
|  | 185 | def valid_path(var_name, *args, **kwargs): | 
|  | 186 |  | 
|  | 187 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 188 | error_message = \ | 
|  | 189 | gv.valid_path(var_value, *args, var_name=var_name, **kwargs) | 
|  | 190 | process_error_message(error_message) | 
|  | 191 |  | 
|  | 192 |  | 
|  | 193 | def valid_list(var_name, *args, **kwargs): | 
|  | 194 |  | 
|  | 195 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 196 | error_message = \ | 
|  | 197 | gv.valid_list(var_value, *args, var_name=var_name, **kwargs) | 
|  | 198 | process_error_message(error_message) | 
|  | 199 |  | 
|  | 200 |  | 
|  | 201 | def valid_dict(var_name, *args, **kwargs): | 
|  | 202 |  | 
|  | 203 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 204 | error_message = \ | 
|  | 205 | gv.valid_dict(var_value, *args, var_name=var_name, **kwargs) | 
|  | 206 | process_error_message(error_message) | 
|  | 207 |  | 
|  | 208 |  | 
| Michael Walsh | be3a815 | 2019-08-20 16:38:19 -0500 | [diff] [blame] | 209 | def valid_program(var_name, *args, **kwargs): | 
|  | 210 |  | 
|  | 211 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 212 | error_message = \ | 
|  | 213 | gv.valid_program(var_value, *args, var_name=var_name, **kwargs) | 
|  | 214 | process_error_message(error_message) | 
|  | 215 |  | 
|  | 216 |  | 
| Michael Walsh | b9d8dfd | 2019-09-11 11:11:12 -0500 | [diff] [blame] | 217 | def valid_length(var_name, *args, **kwargs): | 
|  | 218 |  | 
|  | 219 | var_value, args, kwargs = valid_init(var_name, *args, **kwargs) | 
|  | 220 | error_message = \ | 
|  | 221 | gv.valid_length(var_value, *args, var_name=var_name, **kwargs) | 
|  | 222 | process_error_message(error_message) | 
|  | 223 |  | 
|  | 224 |  | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 225 | # Modify the validation function docstrings by calling customize_doc_string | 
|  | 226 | # for each function in the func_names list. | 
|  | 227 | func_names = [ | 
|  | 228 | "valid_type", "valid_value", "valid_range", "valid_integer", | 
|  | 229 | "valid_dir_path", "valid_file_path", "valid_path", "valid_list", | 
| Michael Walsh | be3a815 | 2019-08-20 16:38:19 -0500 | [diff] [blame] | 230 | "valid_dict", "valid_program" | 
| Michael Walsh | 84230c2 | 2019-08-01 12:23:07 -0500 | [diff] [blame] | 231 | ] | 
|  | 232 |  | 
|  | 233 | for func_name in func_names: | 
|  | 234 | cmd_buf = func_name \ | 
|  | 235 | + ".__doc__ = customize_doc_string(gv.raw_doc_strings['" \ | 
|  | 236 | + func_name + "'])" | 
|  | 237 | exec(cmd_buf) |