blob: 91a68fb79b9850fa067d76b4d8ff7e2cdb231bd6 [file] [log] [blame]
Michael Walsh7423c012016-10-04 10:27:21 -05001#!/usr/bin/env python
2
3r"""
Michael Walsh018e25f2019-08-01 11:27:12 -05004This module provides validation functions like valid_value(), valid_integer(),
5etc.
Michael Walsh7423c012016-10-04 10:27:21 -05006"""
7
Michael Walsh78bdfdd2017-01-10 11:27:30 -06008import os
Michael Walsh7423c012016-10-04 10:27:21 -05009import gen_print as gp
Michael Walshbe3a8152019-08-20 16:38:19 -050010import gen_cmd as gc
Michael Walsh018e25f2019-08-01 11:27:12 -050011import func_args as fa
Michael Walsh7423c012016-10-04 10:27:21 -050012
Michael Walshe23b5ad2018-06-01 14:54:35 -050013exit_on_error = False
14
15
16def set_exit_on_error(value):
17 r"""
18 Set the exit_on_error value to either True or False.
19
Michael Walsh018e25f2019-08-01 11:27:12 -050020 If exit_on_error is set, validation functions like valid_value() will exit
Michael Walshe23b5ad2018-06-01 14:54:35 -050021 the program on error instead of returning False.
22
23 Description of argument(s):
24 value Value to set global exit_on_error to.
25 """
26
27 global exit_on_error
28 exit_on_error = value
29
30
Michael Walsh89eff542019-09-13 16:24:51 -050031def get_var_name(var_name):
Michael Walshe23b5ad2018-06-01 14:54:35 -050032 r"""
Michael Walsh89eff542019-09-13 16:24:51 -050033 If var_name is not None, simply return its value. Otherwise, get the
34 variable name of the first argument used to call the validation function
35 (e.g. valid, valid_integer, etc.) and return it.
Michael Walshe23b5ad2018-06-01 14:54:35 -050036
37 This function is designed solely for use by other functions in this file.
38
39 Example:
40
41 A programmer codes this:
42
43 valid_value(last_name)
44
45 Which results in the following call stack:
46
47 valid_value(last_name)
Michael Walsh018e25f2019-08-01 11:27:12 -050048 -> get_var_name(var_name)
Michael Walshe23b5ad2018-06-01 14:54:35 -050049
50 In this example, this function will return "last_name".
51
52 Example:
53
Michael Walsh018e25f2019-08-01 11:27:12 -050054 err_msg = valid_value(last_name, var_name="some_other_name")
Michael Walshe23b5ad2018-06-01 14:54:35 -050055
56 Which results in the following call stack:
57
Michael Walsh018e25f2019-08-01 11:27:12 -050058 valid_value(var_value, var_name="some_other_name")
Michael Walshe23b5ad2018-06-01 14:54:35 -050059 -> get_var_name(var_name)
60
61 In this example, this function will return "some_other_name".
62
63 Description of argument(s):
64 var_name The name of the variable.
65 """
66
Michael Walsh89eff542019-09-13 16:24:51 -050067 return var_name or gp.get_arg_name(0, 1, stack_frame_ix=3)
Michael Walshe23b5ad2018-06-01 14:54:35 -050068
69
70def process_error_message(error_message):
71 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -050072 Process the error_message in the manner described below.
Michael Walshe23b5ad2018-06-01 14:54:35 -050073
Michael Walsh018e25f2019-08-01 11:27:12 -050074 This function is designed solely for use by other functions in this file.
75
76 NOTE: A blank error_message means that there is no error.
77
78 For the following explanations, assume the caller of this function is a
79 function with the following definition:
Michael Walsh89eff542019-09-13 16:24:51 -050080 valid_value(var_value, valid_values=[], invalid_values=[], var_name=None):
Michael Walsh018e25f2019-08-01 11:27:12 -050081
82 If the user of valid_value() is assigning the valid_value() return value
83 to a variable, process_error_message() will simply return the
84 error_message. This mode of usage is illustrated by the following example:
85
86 error_message = valid_value(var1)
87
88 This mode is useful for callers who wish to validate a variable and then
89 decide for themselves what to do with the error_message (e.g.
90 raise(error_message), BuiltIn().fail(error_message), etc.).
91
92 If the user of valid_value() is NOT assigning the valid_value() return
93 value to a variable, process_error_message() will behave as follows.
94
95 First, if error_message is non-blank, it will be printed to stderr via a
96 call to gp.print_error_report(error_message).
97
98 If exit_on_error is set:
99 - If the error_message is blank, simply return.
100 - If the error_message is non-blank, exit the program with a return code
101 of 1.
102
103 If exit_on_error is NOT set:
104 - If the error_message is blank, return True.
105 - If the error_message is non-blank, return False.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500106
107 Description of argument(s):
108 error_message An error message.
109 """
110
Michael Walsh018e25f2019-08-01 11:27:12 -0500111 # Determine whether the caller's caller is assigning the result to a
112 # variable.
113 l_value = gp.get_arg_name(None, -1, stack_frame_ix=3)
114 if l_value:
115 return error_message
116
Michael Walshe23b5ad2018-06-01 14:54:35 -0500117 if error_message == "":
Michael Walsh018e25f2019-08-01 11:27:12 -0500118 if exit_on_error:
119 return
Michael Walshe23b5ad2018-06-01 14:54:35 -0500120 return True
121
Michael Walsh018e25f2019-08-01 11:27:12 -0500122 gp.print_error_report(error_message, stack_frame_ix=4)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500123 if exit_on_error:
Michael Walsh10a4d982018-10-30 13:07:46 -0500124 exit(1)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500125 return False
126
Michael Walsh7423c012016-10-04 10:27:21 -0500127
Michael Walsh018e25f2019-08-01 11:27:12 -0500128# Note to programmers: All of the validation functions in this module should
129# follow the same basic template:
Michael Walsh89eff542019-09-13 16:24:51 -0500130# def valid_value(var_value, var1, var2, varn, var_name=None):
Michael Walsh018e25f2019-08-01 11:27:12 -0500131#
132# error_message = ""
133# if not valid:
Michael Walsh89eff542019-09-13 16:24:51 -0500134# var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500135# error_message += "The following variable is invalid because...:\n"
136# error_message += gp.sprint_varx(var_name, var_value, gp.blank())
137#
138# return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500139
Michael Walsh018e25f2019-08-01 11:27:12 -0500140
141# The docstring header and footer will be added to each validation function's
142# existing docstring.
143docstring_header = \
144 r"""
145 Determine whether var_value is valid, construct an error_message and call
146 process_error_message(error_message).
147
148 See the process_error_message() function defined in this module for a
149 description of how error messages are processed.
Michael Walsh7423c012016-10-04 10:27:21 -0500150 """
151
Michael Walsh018e25f2019-08-01 11:27:12 -0500152additional_args_docstring_footer = \
153 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500154 var_name The name of the variable whose value is
155 passed in var_value. For the general
156 case, this argument is unnecessary as this
157 function can figure out the var_name.
158 This is provided for Robot callers in
159 which case, this function lacks the
160 ability to determine the variable name.
161 """
162
163
Michael Walsh89eff542019-09-13 16:24:51 -0500164def valid_type(var_value, required_type, var_name=None):
Michael Walsh018e25f2019-08-01 11:27:12 -0500165 r"""
166 The variable value is valid if it is of the required type.
167
168 Examples:
169
170 valid_type(var1, int)
171
172 valid_type(var1, (list, dict))
173
174 Description of argument(s):
175 var_value The value being validated.
176 required_type A type or a tuple of types (e.g. str, int,
177 etc.).
178 """
179
180 error_message = ""
181 if type(required_type) is tuple:
182 if type(var_value) in required_type:
183 return process_error_message(error_message)
184 else:
185 if type(var_value) is required_type:
186 return process_error_message(error_message)
187
188 # If we get to this point, the validation has failed.
Michael Walsh89eff542019-09-13 16:24:51 -0500189 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500190 error_message += "Invalid variable type:\n"
191 error_message += gp.sprint_varx(var_name, var_value,
192 gp.blank() | gp.show_type())
193 error_message += "\n"
194 error_message += gp.sprint_var(required_type)
195
196 return process_error_message(error_message)
197
198
Michael Walsh89eff542019-09-13 16:24:51 -0500199def valid_value(var_value, valid_values=[], invalid_values=[], var_name=None):
Michael Walsh018e25f2019-08-01 11:27:12 -0500200
201 r"""
202 The variable value is valid if it is either contained in the valid_values
203 list or if it is NOT contained in the invalid_values list. If the caller
204 specifies nothing for either of these 2 arguments, invalid_values will be
205 initialized to ['', None]. This is a good way to fail on variables which
206 contain blank values.
207
208 It is illegal to specify both valid_values and invalid values.
209
210 Example:
211
212 var1 = ''
213 valid_value(var1)
214
215 This code would fail because var1 is blank and the default value for
216 invalid_values is ['', None].
217
218 Example:
219 var1 = 'yes'
220 valid_value(var1, valid_values=['yes', 'true'])
221
222 This code would pass.
223
224 Description of argument(s):
225 var_value The value being validated.
226 valid_values A list of valid values. The variable
227 value must be equal to one of these values
228 to be considered valid.
229 invalid_values A list of invalid values. If the variable
230 value is equal to any of these, it is
231 considered invalid.
232 """
233
Michael Walshbec416d2016-11-10 08:54:52 -0600234 error_message = ""
Michael Walshbec416d2016-11-10 08:54:52 -0600235
Michael Walshe23b5ad2018-06-01 14:54:35 -0500236 # Validate this function's arguments.
Michael Walsh7423c012016-10-04 10:27:21 -0500237 len_valid_values = len(valid_values)
238 len_invalid_values = len(invalid_values)
239 if len_valid_values > 0 and len_invalid_values > 0:
Michael Walsh018e25f2019-08-01 11:27:12 -0500240 error_message += "Programmer error - You must provide either an"
241 error_message += " invalid_values list or a valid_values"
242 error_message += " list but NOT both:\n"
243 error_message += gp.sprint_var(invalid_values)
244 error_message += gp.sprint_var(valid_values)
245 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500246
247 if len_valid_values > 0:
248 # Processing the valid_values list.
249 if var_value in valid_values:
Michael Walsh018e25f2019-08-01 11:27:12 -0500250 return process_error_message(error_message)
Michael Walsh89eff542019-09-13 16:24:51 -0500251 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500252 error_message += "Invalid variable value:\n"
253 error_message += gp.sprint_varx(var_name, var_value,
254 gp.blank() | gp.verbose()
255 | gp.show_type())
256 error_message += "\n"
257 error_message += "It must be one of the following values:\n"
258 error_message += "\n"
259 error_message += gp.sprint_var(valid_values,
260 gp.blank() | gp.show_type())
261 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500262
263 if len_invalid_values == 0:
Michael Walshbec416d2016-11-10 08:54:52 -0600264 # Assign default value.
Michael Walsh018e25f2019-08-01 11:27:12 -0500265 invalid_values = ["", None]
Michael Walsh7423c012016-10-04 10:27:21 -0500266
267 # Assertion: We have an invalid_values list. Processing it now.
268 if var_value not in invalid_values:
Michael Walsh018e25f2019-08-01 11:27:12 -0500269 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500270
Michael Walsh89eff542019-09-13 16:24:51 -0500271 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500272 error_message += "Invalid variable value:\n"
273 error_message += gp.sprint_varx(var_name, var_value,
274 gp.blank() | gp.verbose()
275 | gp.show_type())
276 error_message += "\n"
277 error_message += "It must NOT be one of the following values:\n"
278 error_message += "\n"
279 error_message += gp.sprint_var(invalid_values,
280 gp.blank() | gp.show_type())
Michael Walshe23b5ad2018-06-01 14:54:35 -0500281 return process_error_message(error_message)
Michael Walshbec416d2016-11-10 08:54:52 -0600282
Michael Walshbec416d2016-11-10 08:54:52 -0600283
Michael Walsh89eff542019-09-13 16:24:51 -0500284def valid_range(var_value, lower=None, upper=None, var_name=None):
Michael Walshbec416d2016-11-10 08:54:52 -0600285 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500286 The variable value is valid if it is within the specified range.
Michael Walshbec416d2016-11-10 08:54:52 -0600287
Michael Walsh018e25f2019-08-01 11:27:12 -0500288 This function can be used with any type of operands where they can have a
289 greater than/less than relationship to each other (e.g. int, float, str).
290
291 Description of argument(s):
Michael Walshbec416d2016-11-10 08:54:52 -0600292 var_value The value being validated.
Michael Walsh018e25f2019-08-01 11:27:12 -0500293 lower The lower end of the range. If not None,
294 the var_value must be greater than or
295 equal to lower.
296 upper The upper end of the range. If not None,
297 the var_value must be less than or equal
298 to upper.
Michael Walshbec416d2016-11-10 08:54:52 -0600299 """
300
Michael Walshbec416d2016-11-10 08:54:52 -0600301 error_message = ""
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500302 if lower is None and upper is None:
Michael Walsh018e25f2019-08-01 11:27:12 -0500303 return process_error_message(error_message)
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500304 if lower is None and var_value <= upper:
Michael Walsh018e25f2019-08-01 11:27:12 -0500305 return process_error_message(error_message)
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500306 if upper is None and var_value >= lower:
Michael Walsh018e25f2019-08-01 11:27:12 -0500307 return process_error_message(error_message)
308 if lower and upper:
309 if lower > upper:
Michael Walsh89eff542019-09-13 16:24:51 -0500310 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500311 error_message += "Programmer error - the lower value is greater"
312 error_message += " than the upper value:\n"
313 error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type())
314 return process_error_message(error_message)
315 if lower <= var_value <= upper:
316 return process_error_message(error_message)
Michael Walshbec416d2016-11-10 08:54:52 -0600317
Michael Walsh89eff542019-09-13 16:24:51 -0500318 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500319 error_message += "The following variable is not within the expected"
320 error_message += " range:\n"
321 error_message += gp.sprint_varx(var_name, var_value, gp.show_type())
322 error_message += "\n"
323 error_message += "range:\n"
324 error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500325 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500326
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600327
Michael Walsh89eff542019-09-13 16:24:51 -0500328def valid_integer(var_value, lower=None, upper=None, var_name=None):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600329 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500330 The variable value is valid if it is an integer or can be interpreted as
331 an integer (e.g. 7, "7", etc.).
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600332
Michael Walsh018e25f2019-08-01 11:27:12 -0500333 This function also calls valid_range to make sure the integer value is
334 within the specified range (if any).
335
336 Description of argument(s):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600337 var_value The value being validated.
Michael Walsh018e25f2019-08-01 11:27:12 -0500338 lower The lower end of the range. If not None,
339 the var_value must be greater than or
340 equal to lower.
341 upper The upper end of the range. If not None,
342 the var_value must be less than or equal
343 to upper.
344 """
345
346 error_message = ""
Michael Walsh89eff542019-09-13 16:24:51 -0500347 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500348 try:
349 var_value = int(str(var_value), 0)
350 except ValueError:
351 error_message += "Invalid integer value:\n"
352 error_message += gp.sprint_varx(var_name, var_value,
353 gp.blank() | gp.show_type())
354 return process_error_message(error_message)
355
356 # Check the range (if any).
357 if lower:
358 lower = int(str(lower), 0)
359 if upper:
360 upper = int(str(upper), 0)
361 error_message = valid_range(var_value, lower, upper, var_name=var_name)
362
363 return process_error_message(error_message)
364
365
Michael Walsh89eff542019-09-13 16:24:51 -0500366def valid_dir_path(var_value, var_name=None):
Michael Walsh018e25f2019-08-01 11:27:12 -0500367 r"""
368 The variable value is valid if it contains the path of an existing
369 directory.
370
371 Description of argument(s):
372 var_value The value being validated.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600373 """
374
375 error_message = ""
376 if not os.path.isdir(str(var_value)):
Michael Walsh89eff542019-09-13 16:24:51 -0500377 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500378 error_message += "The following directory does not exist:\n"
Michael Walsh00244342019-08-29 10:35:50 -0500379 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600380
Michael Walshe23b5ad2018-06-01 14:54:35 -0500381 return process_error_message(error_message)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600382
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600383
Michael Walsh89eff542019-09-13 16:24:51 -0500384def valid_file_path(var_value, var_name=None):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600385 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500386 The variable value is valid if it contains the path of an existing file.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600387
Michael Walsh018e25f2019-08-01 11:27:12 -0500388 Description of argument(s):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600389 var_value The value being validated.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600390 """
391
392 error_message = ""
393 if not os.path.isfile(str(var_value)):
Michael Walsh89eff542019-09-13 16:24:51 -0500394 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500395 error_message += "The following file does not exist:\n"
Michael Walsh00244342019-08-29 10:35:50 -0500396 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600397
Michael Walshe23b5ad2018-06-01 14:54:35 -0500398 return process_error_message(error_message)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600399
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600400
Michael Walsh89eff542019-09-13 16:24:51 -0500401def valid_path(var_value, var_name=None):
Michael Walshe23b5ad2018-06-01 14:54:35 -0500402 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500403 The variable value is valid if it contains the path of an existing file or
404 directory.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500405
Michael Walsh018e25f2019-08-01 11:27:12 -0500406 Description of argument(s):
Michael Walshe23b5ad2018-06-01 14:54:35 -0500407 var_value The value being validated.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500408 """
409
410 error_message = ""
411 if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))):
Michael Walsh89eff542019-09-13 16:24:51 -0500412 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500413 error_message += "Invalid path (file or directory does not exist):\n"
Michael Walsh00244342019-08-29 10:35:50 -0500414 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walshe23b5ad2018-06-01 14:54:35 -0500415
Michael Walshe23b5ad2018-06-01 14:54:35 -0500416 return process_error_message(error_message)
Michael Walsh2c687e92018-05-09 11:47:56 -0500417
418
Michael Walsh35026be2019-08-14 17:13:39 -0500419def valid_list(var_value, valid_values=[], invalid_values=[],
Michael Walsh89eff542019-09-13 16:24:51 -0500420 required_values=[], fail_on_empty=False, var_name=None):
Michael Walsh2c687e92018-05-09 11:47:56 -0500421 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500422 The variable value is valid if it is a list where each entry can be found
Michael Walsh35026be2019-08-14 17:13:39 -0500423 in the valid_values list or if none of its values can be found in the
424 invalid_values list or if all of the values in the required_values list
425 can be found in var_value.
426
427 The caller may only specify one of these 3 arguments: valid_values,
428 invalid_values, required_values.
Michael Walsh2c687e92018-05-09 11:47:56 -0500429
Michael Walsh018e25f2019-08-01 11:27:12 -0500430 Description of argument(s):
431 var_value The value being validated.
Michael Walshca193992018-08-02 17:20:00 -0500432 valid_values A list of valid values. Each element in
433 the var_value list must be equal to one of
434 these values to be considered valid.
Michael Walsh35026be2019-08-14 17:13:39 -0500435 invalid_values A list of invalid values. If any element
436 in var_value is equal to any of the values
437 in this argument, var_value is considered
438 invalid.
439 required_values Every value in required_values must be
440 found in var_value. Otherwise, var_value
441 is considered invalid.
Michael Walsh018e25f2019-08-01 11:27:12 -0500442 fail_on_empty Indicates that an empty list for the
443 variable value should be considered an
444 error.
Michael Walshca193992018-08-02 17:20:00 -0500445 """
446
447 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500448
Michael Walsh35026be2019-08-14 17:13:39 -0500449 # Validate this function's arguments.
450 len_valid_values = len(valid_values)
451 len_invalid_values = len(invalid_values)
452 len_required_values = len(required_values)
453 if (len_valid_values + len_invalid_values + len_required_values) > 1:
454 error_message += "Programmer error - You must provide only one of the"
455 error_message += " following: valid_values, invalid_values,"
456 error_message += " required_values.\n"
457 error_message += gp.sprint_var(invalid_values)
458 error_message += gp.sprint_var(valid_values)
459 error_message += gp.sprint_var(required_values)
460 return process_error_message(error_message)
461
Michael Walsh018e25f2019-08-01 11:27:12 -0500462 if type(var_value) is not list:
Michael Walsh89eff542019-09-13 16:24:51 -0500463 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500464 error_message = valid_type(var_value, list, var_name=var_name)
465 if error_message:
466 return process_error_message(error_message)
467
468 if fail_on_empty and len(var_value) == 0:
Michael Walsh89eff542019-09-13 16:24:51 -0500469 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500470 error_message += "Invalid empty list:\n"
471 error_message += gp.sprint_varx(var_name, var_value, gp.show_type())
472 return process_error_message(error_message)
Michael Walshca193992018-08-02 17:20:00 -0500473
Michael Walsh35026be2019-08-14 17:13:39 -0500474 if len(required_values):
475 found_error = 0
476 display_required_values = list(required_values)
477 for ix in range(0, len(required_values)):
478 if required_values[ix] not in var_value:
479 found_error = 1
480 display_required_values[ix] = \
481 str(display_required_values[ix]) + "*"
482 if found_error:
Michael Walsh89eff542019-09-13 16:24:51 -0500483 var_name = get_var_name(var_name)
Michael Walsh35026be2019-08-14 17:13:39 -0500484 error_message += "The following list is invalid:\n"
485 error_message += gp.sprint_varx(var_name, var_value,
486 gp.blank() | gp.show_type())
487 error_message += "\n"
488 error_message += "Because some of the values in the "
489 error_message += "required_values list are not present (see"
490 error_message += " entries marked with \"*\"):\n"
491 error_message += "\n"
492 error_message += gp.sprint_varx('required_values',
493 display_required_values,
494 gp.blank() | gp.show_type())
495 error_message += "\n"
496
497 return process_error_message(error_message)
498
499 if len(invalid_values):
500 found_error = 0
501 display_var_value = list(var_value)
502 for ix in range(0, len(var_value)):
503 if var_value[ix] in invalid_values:
504 found_error = 1
505 display_var_value[ix] = str(var_value[ix]) + "*"
506
507 if found_error:
Michael Walsh89eff542019-09-13 16:24:51 -0500508 var_name = get_var_name(var_name)
Michael Walsh35026be2019-08-14 17:13:39 -0500509 error_message += "The following list is invalid (see entries"
510 error_message += " marked with \"*\"):\n"
511 error_message += gp.sprint_varx(var_name, display_var_value,
512 gp.blank() | gp.show_type())
513 error_message += "\n"
514 error_message += gp.sprint_var(invalid_values, gp.show_type())
515 return process_error_message(error_message)
516
Michael Walshca193992018-08-02 17:20:00 -0500517 found_error = 0
518 display_var_value = list(var_value)
519 for ix in range(0, len(var_value)):
520 if var_value[ix] not in valid_values:
521 found_error = 1
Michael Walsh35026be2019-08-14 17:13:39 -0500522 display_var_value[ix] = str(var_value[ix]) + "*"
Michael Walshca193992018-08-02 17:20:00 -0500523
524 if found_error:
Michael Walsh89eff542019-09-13 16:24:51 -0500525 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500526 error_message += "The following list is invalid (see entries marked"
527 error_message += " with \"*\"):\n"
528 error_message += gp.sprint_varx(var_name, display_var_value,
529 gp.blank() | gp.show_type())
530 error_message += "\n"
Michael Walsh35026be2019-08-14 17:13:39 -0500531 error_message += gp.sprint_var(valid_values, gp.show_type())
Michael Walsh018e25f2019-08-01 11:27:12 -0500532 return process_error_message(error_message)
Michael Walshca193992018-08-02 17:20:00 -0500533
Michael Walshca193992018-08-02 17:20:00 -0500534 return process_error_message(error_message)
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500535
536
Michael Walsh89eff542019-09-13 16:24:51 -0500537def valid_dict(var_value, required_keys=[], var_name=None):
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500538 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500539 The variable value is valid if it is a dictionary containing all of the
540 required keys.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500541
Michael Walsh018e25f2019-08-01 11:27:12 -0500542 Description of argument(s):
543 var_value The value being validated.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500544 required_keys A list of keys which must be found in the
545 dictionary for it to be considered valid.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500546 """
547
548 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500549 missing_keys = list(set(required_keys) - set(var_value.keys()))
550 if len(missing_keys) > 0:
Michael Walsh89eff542019-09-13 16:24:51 -0500551 var_name = get_var_name(var_name)
Michael Walsh018e25f2019-08-01 11:27:12 -0500552 error_message += "The following dictionary is invalid because it is"
553 error_message += " missing required keys:\n"
554 error_message += gp.sprint_varx(var_name, var_value,
555 gp.blank() | gp.show_type())
556 error_message += "\n"
Michael Walsh35026be2019-08-14 17:13:39 -0500557 error_message += gp.sprint_var(missing_keys, gp.show_type())
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500558 return process_error_message(error_message)
Michael Walsh018e25f2019-08-01 11:27:12 -0500559
560
Michael Walsh89eff542019-09-13 16:24:51 -0500561def valid_program(var_value, var_name=None):
Michael Walshbe3a8152019-08-20 16:38:19 -0500562 r"""
563 The variable value is valid if it contains the name of a program which can
564 be located using the "which" command.
565
566 Description of argument(s):
567 var_value The value being validated.
568 """
569
570 error_message = ""
571 rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0,
572 ignore_err=1)
573 if rc:
Michael Walsh89eff542019-09-13 16:24:51 -0500574 var_name = get_var_name(var_name)
Michael Walshbe3a8152019-08-20 16:38:19 -0500575 error_message += "The following required program could not be found"
576 error_message += " using the $PATH environment variable:\n"
Michael Walsh00244342019-08-29 10:35:50 -0500577 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walshbe3a8152019-08-20 16:38:19 -0500578 PATH = os.environ.get("PATH", "").split(":")
579 error_message += "\n"
580 error_message += gp.sprint_var(PATH)
581 return process_error_message(error_message)
582
583
Michael Walsh89eff542019-09-13 16:24:51 -0500584def valid_length(var_value, min_length=None, max_length=None, var_name=None):
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500585 r"""
586 The variable value is valid if it is an object (e.g. list, dictionary)
587 whose length is within the specified range.
588
589 Description of argument(s):
590 var_value The value being validated.
591 min_length The minimum length of the object. If not
592 None, the length of var_value must be
593 greater than or equal to min_length.
594 max_length The maximum length of the object. If not
595 None, the length of var_value must be less
596 than or equal to min_length.
597 """
598
599 error_message = ""
600 length = len(var_value)
601 error_message = valid_range(length, min_length, max_length)
602 if error_message:
Michael Walsh89eff542019-09-13 16:24:51 -0500603 var_name = get_var_name(var_name)
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500604 error_message = "The length of the following object is not within the"
605 error_message += " expected range:\n"
606 error_message += gp.sprint_var(length)
607 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
608 error_message += "\n"
609 error_message += gp.sprint_vars(min_length, max_length)
610 return process_error_message(error_message)
611
612 return process_error_message(error_message)
613
614
Michael Walsh018e25f2019-08-01 11:27:12 -0500615# Modify selected function docstrings by adding headers/footers.
616
617func_names = [
618 "valid_type", "valid_value", "valid_range", "valid_integer",
619 "valid_dir_path", "valid_file_path", "valid_path", "valid_list",
Michael Walsh89eff542019-09-13 16:24:51 -0500620 "valid_dict", "valid_program", "valid_length"
Michael Walsh018e25f2019-08-01 11:27:12 -0500621]
622
623raw_doc_strings = {}
624
625for func_name in func_names:
626 cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name
627 cmd_buf += ".__doc__"
628 exec(cmd_buf)
629 cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name
630 cmd_buf += ".__doc__.rstrip(\" \\n\") + additional_args_docstring_footer"
631 exec(cmd_buf)