blob: 87250770403ec041581665e3c157befb7f2c54dd [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 Walshbe3a8152019-08-20 16:38:19 -05009import re
Michael Walsh7423c012016-10-04 10:27:21 -050010import gen_print as gp
Michael Walshbe3a8152019-08-20 16:38:19 -050011import gen_cmd as gc
Michael Walsh018e25f2019-08-01 11:27:12 -050012import func_args as fa
Michael Walsh7423c012016-10-04 10:27:21 -050013
Michael Walshe23b5ad2018-06-01 14:54:35 -050014exit_on_error = False
15
16
17def set_exit_on_error(value):
18 r"""
19 Set the exit_on_error value to either True or False.
20
Michael Walsh018e25f2019-08-01 11:27:12 -050021 If exit_on_error is set, validation functions like valid_value() will exit
Michael Walshe23b5ad2018-06-01 14:54:35 -050022 the program on error instead of returning False.
23
24 Description of argument(s):
25 value Value to set global exit_on_error to.
26 """
27
28 global exit_on_error
29 exit_on_error = value
30
31
Michael Walsh018e25f2019-08-01 11:27:12 -050032def get_var_name(*args, **kwargs):
Michael Walshe23b5ad2018-06-01 14:54:35 -050033 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -050034 If args/kwargs contain a var_name, simply return its value. Otherwise,
35 get the variable name of the first argument used to call the validation
36 function (e.g. valid, valid_integer, etc.) and return it.
Michael Walshe23b5ad2018-06-01 14:54:35 -050037
38 This function is designed solely for use by other functions in this file.
39
40 Example:
41
42 A programmer codes this:
43
44 valid_value(last_name)
45
46 Which results in the following call stack:
47
48 valid_value(last_name)
Michael Walsh018e25f2019-08-01 11:27:12 -050049 -> get_var_name(var_name)
Michael Walshe23b5ad2018-06-01 14:54:35 -050050
51 In this example, this function will return "last_name".
52
53 Example:
54
Michael Walsh018e25f2019-08-01 11:27:12 -050055 err_msg = valid_value(last_name, var_name="some_other_name")
Michael Walshe23b5ad2018-06-01 14:54:35 -050056
57 Which results in the following call stack:
58
Michael Walsh018e25f2019-08-01 11:27:12 -050059 valid_value(var_value, var_name="some_other_name")
Michael Walshe23b5ad2018-06-01 14:54:35 -050060 -> get_var_name(var_name)
61
62 In this example, this function will return "some_other_name".
63
64 Description of argument(s):
65 var_name The name of the variable.
66 """
67
Michael Walsh018e25f2019-08-01 11:27:12 -050068 var_name, args, kwargs = fa.pop_arg(*args, **kwargs)
69 if var_name:
Michael Walshe23b5ad2018-06-01 14:54:35 -050070 return var_name
Michael Walsh018e25f2019-08-01 11:27:12 -050071 return gp.get_arg_name(0, 1, stack_frame_ix=3)
Michael Walshe23b5ad2018-06-01 14:54:35 -050072
73
74def process_error_message(error_message):
75 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -050076 Process the error_message in the manner described below.
Michael Walshe23b5ad2018-06-01 14:54:35 -050077
Michael Walsh018e25f2019-08-01 11:27:12 -050078 This function is designed solely for use by other functions in this file.
79
80 NOTE: A blank error_message means that there is no error.
81
82 For the following explanations, assume the caller of this function is a
83 function with the following definition:
84 valid_value(var_value, valid_values=[], invalid_values=[], *args,
85 **kwargs):
86
87 If the user of valid_value() is assigning the valid_value() return value
88 to a variable, process_error_message() will simply return the
89 error_message. This mode of usage is illustrated by the following example:
90
91 error_message = valid_value(var1)
92
93 This mode is useful for callers who wish to validate a variable and then
94 decide for themselves what to do with the error_message (e.g.
95 raise(error_message), BuiltIn().fail(error_message), etc.).
96
97 If the user of valid_value() is NOT assigning the valid_value() return
98 value to a variable, process_error_message() will behave as follows.
99
100 First, if error_message is non-blank, it will be printed to stderr via a
101 call to gp.print_error_report(error_message).
102
103 If exit_on_error is set:
104 - If the error_message is blank, simply return.
105 - If the error_message is non-blank, exit the program with a return code
106 of 1.
107
108 If exit_on_error is NOT set:
109 - If the error_message is blank, return True.
110 - If the error_message is non-blank, return False.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500111
112 Description of argument(s):
113 error_message An error message.
114 """
115
Michael Walsh018e25f2019-08-01 11:27:12 -0500116 # Determine whether the caller's caller is assigning the result to a
117 # variable.
118 l_value = gp.get_arg_name(None, -1, stack_frame_ix=3)
119 if l_value:
120 return error_message
121
Michael Walshe23b5ad2018-06-01 14:54:35 -0500122 if error_message == "":
Michael Walsh018e25f2019-08-01 11:27:12 -0500123 if exit_on_error:
124 return
Michael Walshe23b5ad2018-06-01 14:54:35 -0500125 return True
126
Michael Walsh018e25f2019-08-01 11:27:12 -0500127 gp.print_error_report(error_message, stack_frame_ix=4)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500128 if exit_on_error:
Michael Walsh10a4d982018-10-30 13:07:46 -0500129 exit(1)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500130 return False
131
Michael Walsh7423c012016-10-04 10:27:21 -0500132
Michael Walsh018e25f2019-08-01 11:27:12 -0500133# Note to programmers: All of the validation functions in this module should
134# follow the same basic template:
135# def valid_value(var_value, var1, var2, varn, *args, **kwargs):
136#
137# error_message = ""
138# if not valid:
139# var_name = get_var_name(*args, **kwargs)
140# error_message += "The following variable is invalid because...:\n"
141# error_message += gp.sprint_varx(var_name, var_value, gp.blank())
142#
143# return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500144
Michael Walsh018e25f2019-08-01 11:27:12 -0500145
146# The docstring header and footer will be added to each validation function's
147# existing docstring.
148docstring_header = \
149 r"""
150 Determine whether var_value is valid, construct an error_message and call
151 process_error_message(error_message).
152
153 See the process_error_message() function defined in this module for a
154 description of how error messages are processed.
Michael Walsh7423c012016-10-04 10:27:21 -0500155 """
156
Michael Walsh018e25f2019-08-01 11:27:12 -0500157additional_args_docstring_footer = \
158 r"""
159 args Additional positional arguments (described
160 below).
161 kwargs Additional keyword arguments (described
162 below).
163
164 Additional argument(s):
165 var_name The name of the variable whose value is
166 passed in var_value. For the general
167 case, this argument is unnecessary as this
168 function can figure out the var_name.
169 This is provided for Robot callers in
170 which case, this function lacks the
171 ability to determine the variable name.
172 """
173
174
175def valid_type(var_value, required_type, *args, **kwargs):
176 r"""
177 The variable value is valid if it is of the required type.
178
179 Examples:
180
181 valid_type(var1, int)
182
183 valid_type(var1, (list, dict))
184
185 Description of argument(s):
186 var_value The value being validated.
187 required_type A type or a tuple of types (e.g. str, int,
188 etc.).
189 """
190
191 error_message = ""
192 if type(required_type) is tuple:
193 if type(var_value) in required_type:
194 return process_error_message(error_message)
195 else:
196 if type(var_value) is required_type:
197 return process_error_message(error_message)
198
199 # If we get to this point, the validation has failed.
200 var_name = get_var_name(*args, **kwargs)
201 error_message += "Invalid variable type:\n"
202 error_message += gp.sprint_varx(var_name, var_value,
203 gp.blank() | gp.show_type())
204 error_message += "\n"
205 error_message += gp.sprint_var(required_type)
206
207 return process_error_message(error_message)
208
209
210def valid_value(var_value, valid_values=[], invalid_values=[], *args,
211 **kwargs):
212
213 r"""
214 The variable value is valid if it is either contained in the valid_values
215 list or if it is NOT contained in the invalid_values list. If the caller
216 specifies nothing for either of these 2 arguments, invalid_values will be
217 initialized to ['', None]. This is a good way to fail on variables which
218 contain blank values.
219
220 It is illegal to specify both valid_values and invalid values.
221
222 Example:
223
224 var1 = ''
225 valid_value(var1)
226
227 This code would fail because var1 is blank and the default value for
228 invalid_values is ['', None].
229
230 Example:
231 var1 = 'yes'
232 valid_value(var1, valid_values=['yes', 'true'])
233
234 This code would pass.
235
236 Description of argument(s):
237 var_value The value being validated.
238 valid_values A list of valid values. The variable
239 value must be equal to one of these values
240 to be considered valid.
241 invalid_values A list of invalid values. If the variable
242 value is equal to any of these, it is
243 considered invalid.
244 """
245
Michael Walshbec416d2016-11-10 08:54:52 -0600246 error_message = ""
Michael Walshbec416d2016-11-10 08:54:52 -0600247
Michael Walshe23b5ad2018-06-01 14:54:35 -0500248 # Validate this function's arguments.
Michael Walsh7423c012016-10-04 10:27:21 -0500249 len_valid_values = len(valid_values)
250 len_invalid_values = len(invalid_values)
251 if len_valid_values > 0 and len_invalid_values > 0:
Michael Walsh018e25f2019-08-01 11:27:12 -0500252 error_message += "Programmer error - You must provide either an"
253 error_message += " invalid_values list or a valid_values"
254 error_message += " list but NOT both:\n"
255 error_message += gp.sprint_var(invalid_values)
256 error_message += gp.sprint_var(valid_values)
257 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500258
259 if len_valid_values > 0:
260 # Processing the valid_values list.
261 if var_value in valid_values:
Michael Walsh018e25f2019-08-01 11:27:12 -0500262 return process_error_message(error_message)
263 var_name = get_var_name(*args, **kwargs)
264 error_message += "Invalid variable value:\n"
265 error_message += gp.sprint_varx(var_name, var_value,
266 gp.blank() | gp.verbose()
267 | gp.show_type())
268 error_message += "\n"
269 error_message += "It must be one of the following values:\n"
270 error_message += "\n"
271 error_message += gp.sprint_var(valid_values,
272 gp.blank() | gp.show_type())
273 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500274
275 if len_invalid_values == 0:
Michael Walshbec416d2016-11-10 08:54:52 -0600276 # Assign default value.
Michael Walsh018e25f2019-08-01 11:27:12 -0500277 invalid_values = ["", None]
Michael Walsh7423c012016-10-04 10:27:21 -0500278
279 # Assertion: We have an invalid_values list. Processing it now.
280 if var_value not in invalid_values:
Michael Walsh018e25f2019-08-01 11:27:12 -0500281 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500282
Michael Walsh018e25f2019-08-01 11:27:12 -0500283 var_name = get_var_name(*args, **kwargs)
284 error_message += "Invalid variable value:\n"
285 error_message += gp.sprint_varx(var_name, var_value,
286 gp.blank() | gp.verbose()
287 | gp.show_type())
288 error_message += "\n"
289 error_message += "It must NOT be one of the following values:\n"
290 error_message += "\n"
291 error_message += gp.sprint_var(invalid_values,
292 gp.blank() | gp.show_type())
Michael Walshe23b5ad2018-06-01 14:54:35 -0500293 return process_error_message(error_message)
Michael Walshbec416d2016-11-10 08:54:52 -0600294
Michael Walshbec416d2016-11-10 08:54:52 -0600295
Michael Walsh018e25f2019-08-01 11:27:12 -0500296def valid_range(var_value, lower=None, upper=None, *args, **kwargs):
Michael Walshbec416d2016-11-10 08:54:52 -0600297 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500298 The variable value is valid if it is within the specified range.
Michael Walshbec416d2016-11-10 08:54:52 -0600299
Michael Walsh018e25f2019-08-01 11:27:12 -0500300 This function can be used with any type of operands where they can have a
301 greater than/less than relationship to each other (e.g. int, float, str).
302
303 Description of argument(s):
Michael Walshbec416d2016-11-10 08:54:52 -0600304 var_value The value being validated.
Michael Walsh018e25f2019-08-01 11:27:12 -0500305 lower The lower end of the range. If not None,
306 the var_value must be greater than or
307 equal to lower.
308 upper The upper end of the range. If not None,
309 the var_value must be less than or equal
310 to upper.
Michael Walshbec416d2016-11-10 08:54:52 -0600311 """
312
Michael Walshbec416d2016-11-10 08:54:52 -0600313 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500314 if not lower and not upper:
315 return process_error_message(error_message)
316 if not lower and var_value <= upper:
317 return process_error_message(error_message)
318 if not upper and var_value >= lower:
319 return process_error_message(error_message)
320 if lower and upper:
321 if lower > upper:
322 var_name = get_var_name(*args, **kwargs)
323 error_message += "Programmer error - the lower value is greater"
324 error_message += " than the upper value:\n"
325 error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type())
326 return process_error_message(error_message)
327 if lower <= var_value <= upper:
328 return process_error_message(error_message)
Michael Walshbec416d2016-11-10 08:54:52 -0600329
Michael Walsh018e25f2019-08-01 11:27:12 -0500330 var_name = get_var_name(*args, **kwargs)
331 error_message += "The following variable is not within the expected"
332 error_message += " range:\n"
333 error_message += gp.sprint_varx(var_name, var_value, gp.show_type())
334 error_message += "\n"
335 error_message += "range:\n"
336 error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500337 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500338
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600339
Michael Walsh018e25f2019-08-01 11:27:12 -0500340def valid_integer(var_value, lower=None, upper=None, *args, **kwargs):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600341 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500342 The variable value is valid if it is an integer or can be interpreted as
343 an integer (e.g. 7, "7", etc.).
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600344
Michael Walsh018e25f2019-08-01 11:27:12 -0500345 This function also calls valid_range to make sure the integer value is
346 within the specified range (if any).
347
348 Description of argument(s):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600349 var_value The value being validated.
Michael Walsh018e25f2019-08-01 11:27:12 -0500350 lower The lower end of the range. If not None,
351 the var_value must be greater than or
352 equal to lower.
353 upper The upper end of the range. If not None,
354 the var_value must be less than or equal
355 to upper.
356 """
357
358 error_message = ""
359 var_name = get_var_name(*args, **kwargs)
360 try:
361 var_value = int(str(var_value), 0)
362 except ValueError:
363 error_message += "Invalid integer value:\n"
364 error_message += gp.sprint_varx(var_name, var_value,
365 gp.blank() | gp.show_type())
366 return process_error_message(error_message)
367
368 # Check the range (if any).
369 if lower:
370 lower = int(str(lower), 0)
371 if upper:
372 upper = int(str(upper), 0)
373 error_message = valid_range(var_value, lower, upper, var_name=var_name)
374
375 return process_error_message(error_message)
376
377
378def valid_dir_path(var_value, *args, **kwargs):
379 r"""
380 The variable value is valid if it contains the path of an existing
381 directory.
382
383 Description of argument(s):
384 var_value The value being validated.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600385 """
386
387 error_message = ""
388 if not os.path.isdir(str(var_value)):
Michael Walsh018e25f2019-08-01 11:27:12 -0500389 var_name = get_var_name(*args, **kwargs)
390 error_message += "The following directory does not exist:\n"
391 error_message += gp.sprint_varx(var_name, var_value)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600392
Michael Walshe23b5ad2018-06-01 14:54:35 -0500393 return process_error_message(error_message)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600394
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600395
Michael Walsh018e25f2019-08-01 11:27:12 -0500396def valid_file_path(var_value, *args, **kwargs):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600397 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500398 The variable value is valid if it contains the path of an existing file.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600399
Michael Walsh018e25f2019-08-01 11:27:12 -0500400 Description of argument(s):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600401 var_value The value being validated.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600402 """
403
404 error_message = ""
405 if not os.path.isfile(str(var_value)):
Michael Walsh018e25f2019-08-01 11:27:12 -0500406 var_name = get_var_name(*args, **kwargs)
407 error_message += "The following file does not exist:\n"
408 error_message += gp.sprint_varx(var_name, var_value)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600409
Michael Walshe23b5ad2018-06-01 14:54:35 -0500410 return process_error_message(error_message)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600411
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600412
Michael Walsh018e25f2019-08-01 11:27:12 -0500413def valid_path(var_value, *args, **kwargs):
Michael Walshe23b5ad2018-06-01 14:54:35 -0500414 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500415 The variable value is valid if it contains the path of an existing file or
416 directory.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500417
Michael Walsh018e25f2019-08-01 11:27:12 -0500418 Description of argument(s):
Michael Walshe23b5ad2018-06-01 14:54:35 -0500419 var_value The value being validated.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500420 """
421
422 error_message = ""
423 if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))):
Michael Walsh018e25f2019-08-01 11:27:12 -0500424 var_name = get_var_name(*args, **kwargs)
425 error_message += "Invalid path (file or directory does not exist):\n"
426 error_message += gp.sprint_varx(var_name, var_value)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500427
Michael Walshe23b5ad2018-06-01 14:54:35 -0500428 return process_error_message(error_message)
Michael Walsh2c687e92018-05-09 11:47:56 -0500429
430
Michael Walsh35026be2019-08-14 17:13:39 -0500431def valid_list(var_value, valid_values=[], invalid_values=[],
432 required_values=[], fail_on_empty=False, *args, **kwargs):
Michael Walsh2c687e92018-05-09 11:47:56 -0500433 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500434 The variable value is valid if it is a list where each entry can be found
Michael Walsh35026be2019-08-14 17:13:39 -0500435 in the valid_values list or if none of its values can be found in the
436 invalid_values list or if all of the values in the required_values list
437 can be found in var_value.
438
439 The caller may only specify one of these 3 arguments: valid_values,
440 invalid_values, required_values.
Michael Walsh2c687e92018-05-09 11:47:56 -0500441
Michael Walsh018e25f2019-08-01 11:27:12 -0500442 Description of argument(s):
443 var_value The value being validated.
Michael Walshca193992018-08-02 17:20:00 -0500444 valid_values A list of valid values. Each element in
445 the var_value list must be equal to one of
446 these values to be considered valid.
Michael Walsh35026be2019-08-14 17:13:39 -0500447 invalid_values A list of invalid values. If any element
448 in var_value is equal to any of the values
449 in this argument, var_value is considered
450 invalid.
451 required_values Every value in required_values must be
452 found in var_value. Otherwise, var_value
453 is considered invalid.
Michael Walsh018e25f2019-08-01 11:27:12 -0500454 fail_on_empty Indicates that an empty list for the
455 variable value should be considered an
456 error.
Michael Walshca193992018-08-02 17:20:00 -0500457 """
458
459 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500460
Michael Walsh35026be2019-08-14 17:13:39 -0500461 # Validate this function's arguments.
462 len_valid_values = len(valid_values)
463 len_invalid_values = len(invalid_values)
464 len_required_values = len(required_values)
465 if (len_valid_values + len_invalid_values + len_required_values) > 1:
466 error_message += "Programmer error - You must provide only one of the"
467 error_message += " following: valid_values, invalid_values,"
468 error_message += " required_values.\n"
469 error_message += gp.sprint_var(invalid_values)
470 error_message += gp.sprint_var(valid_values)
471 error_message += gp.sprint_var(required_values)
472 return process_error_message(error_message)
473
Michael Walsh018e25f2019-08-01 11:27:12 -0500474 if type(var_value) is not list:
475 var_name = get_var_name(*args, **kwargs)
476 error_message = valid_type(var_value, list, var_name=var_name)
477 if error_message:
478 return process_error_message(error_message)
479
480 if fail_on_empty and len(var_value) == 0:
481 var_name = get_var_name(*args, **kwargs)
482 error_message += "Invalid empty list:\n"
483 error_message += gp.sprint_varx(var_name, var_value, gp.show_type())
484 return process_error_message(error_message)
Michael Walshca193992018-08-02 17:20:00 -0500485
Michael Walsh35026be2019-08-14 17:13:39 -0500486 if len(required_values):
487 found_error = 0
488 display_required_values = list(required_values)
489 for ix in range(0, len(required_values)):
490 if required_values[ix] not in var_value:
491 found_error = 1
492 display_required_values[ix] = \
493 str(display_required_values[ix]) + "*"
494 if found_error:
495 var_name = get_var_name(*args, **kwargs)
496 error_message += "The following list is invalid:\n"
497 error_message += gp.sprint_varx(var_name, var_value,
498 gp.blank() | gp.show_type())
499 error_message += "\n"
500 error_message += "Because some of the values in the "
501 error_message += "required_values list are not present (see"
502 error_message += " entries marked with \"*\"):\n"
503 error_message += "\n"
504 error_message += gp.sprint_varx('required_values',
505 display_required_values,
506 gp.blank() | gp.show_type())
507 error_message += "\n"
508
509 return process_error_message(error_message)
510
511 if len(invalid_values):
512 found_error = 0
513 display_var_value = list(var_value)
514 for ix in range(0, len(var_value)):
515 if var_value[ix] in invalid_values:
516 found_error = 1
517 display_var_value[ix] = str(var_value[ix]) + "*"
518
519 if found_error:
520 var_name = get_var_name(*args, **kwargs)
521 error_message += "The following list is invalid (see entries"
522 error_message += " marked with \"*\"):\n"
523 error_message += gp.sprint_varx(var_name, display_var_value,
524 gp.blank() | gp.show_type())
525 error_message += "\n"
526 error_message += gp.sprint_var(invalid_values, gp.show_type())
527 return process_error_message(error_message)
528
Michael Walshca193992018-08-02 17:20:00 -0500529 found_error = 0
530 display_var_value = list(var_value)
531 for ix in range(0, len(var_value)):
532 if var_value[ix] not in valid_values:
533 found_error = 1
Michael Walsh35026be2019-08-14 17:13:39 -0500534 display_var_value[ix] = str(var_value[ix]) + "*"
Michael Walshca193992018-08-02 17:20:00 -0500535
536 if found_error:
Michael Walsh018e25f2019-08-01 11:27:12 -0500537 var_name = get_var_name(*args, **kwargs)
538 error_message += "The following list is invalid (see entries marked"
539 error_message += " with \"*\"):\n"
540 error_message += gp.sprint_varx(var_name, display_var_value,
541 gp.blank() | gp.show_type())
542 error_message += "\n"
Michael Walsh35026be2019-08-14 17:13:39 -0500543 error_message += gp.sprint_var(valid_values, gp.show_type())
Michael Walsh018e25f2019-08-01 11:27:12 -0500544 return process_error_message(error_message)
Michael Walshca193992018-08-02 17:20:00 -0500545
Michael Walshca193992018-08-02 17:20:00 -0500546 return process_error_message(error_message)
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500547
548
Michael Walsh018e25f2019-08-01 11:27:12 -0500549def valid_dict(var_value, required_keys=[], *args, **kwargs):
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500550 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500551 The variable value is valid if it is a dictionary containing all of the
552 required keys.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500553
Michael Walsh018e25f2019-08-01 11:27:12 -0500554 Description of argument(s):
555 var_value The value being validated.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500556 required_keys A list of keys which must be found in the
557 dictionary for it to be considered valid.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500558 """
559
560 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500561 missing_keys = list(set(required_keys) - set(var_value.keys()))
562 if len(missing_keys) > 0:
563 var_name = get_var_name(*args, **kwargs)
564 error_message += "The following dictionary is invalid because it is"
565 error_message += " missing required keys:\n"
566 error_message += gp.sprint_varx(var_name, var_value,
567 gp.blank() | gp.show_type())
568 error_message += "\n"
Michael Walsh35026be2019-08-14 17:13:39 -0500569 error_message += gp.sprint_var(missing_keys, gp.show_type())
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500570 return process_error_message(error_message)
Michael Walsh018e25f2019-08-01 11:27:12 -0500571
572
Michael Walshbe3a8152019-08-20 16:38:19 -0500573def valid_program(var_value, *args, **kwargs):
574 r"""
575 The variable value is valid if it contains the name of a program which can
576 be located using the "which" command.
577
578 Description of argument(s):
579 var_value The value being validated.
580 """
581
582 error_message = ""
583 rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0,
584 ignore_err=1)
585 if rc:
586 var_name = get_var_name(*args, **kwargs)
587 error_message += "The following required program could not be found"
588 error_message += " using the $PATH environment variable:\n"
589 error_message += gp.sprint_varx(var_name, var_value)
590 PATH = os.environ.get("PATH", "").split(":")
591 error_message += "\n"
592 error_message += gp.sprint_var(PATH)
593 return process_error_message(error_message)
594
595
Michael Walsh018e25f2019-08-01 11:27:12 -0500596# Modify selected function docstrings by adding headers/footers.
597
598func_names = [
599 "valid_type", "valid_value", "valid_range", "valid_integer",
600 "valid_dir_path", "valid_file_path", "valid_path", "valid_list",
Michael Walshbe3a8152019-08-20 16:38:19 -0500601 "valid_dict", "valid_program"
Michael Walsh018e25f2019-08-01 11:27:12 -0500602]
603
604raw_doc_strings = {}
605
606for func_name in func_names:
607 cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name
608 cmd_buf += ".__doc__"
609 exec(cmd_buf)
610 cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name
611 cmd_buf += ".__doc__.rstrip(\" \\n\") + additional_args_docstring_footer"
612 exec(cmd_buf)