blob: 1faf3a72dee74cd9890705aa1ca138218fc59806 [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 Walsh018e25f2019-08-01 11:27:12 -050031def get_var_name(*args, **kwargs):
Michael Walshe23b5ad2018-06-01 14:54:35 -050032 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -050033 If args/kwargs contain a var_name, simply return its value. Otherwise,
34 get the variable name of the first argument used to call the validation
35 function (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 Walsh018e25f2019-08-01 11:27:12 -050067 var_name, args, kwargs = fa.pop_arg(*args, **kwargs)
68 if var_name:
Michael Walshe23b5ad2018-06-01 14:54:35 -050069 return var_name
Michael Walsh018e25f2019-08-01 11:27:12 -050070 return gp.get_arg_name(0, 1, stack_frame_ix=3)
Michael Walshe23b5ad2018-06-01 14:54:35 -050071
72
73def process_error_message(error_message):
74 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -050075 Process the error_message in the manner described below.
Michael Walshe23b5ad2018-06-01 14:54:35 -050076
Michael Walsh018e25f2019-08-01 11:27:12 -050077 This function is designed solely for use by other functions in this file.
78
79 NOTE: A blank error_message means that there is no error.
80
81 For the following explanations, assume the caller of this function is a
82 function with the following definition:
83 valid_value(var_value, valid_values=[], invalid_values=[], *args,
84 **kwargs):
85
86 If the user of valid_value() is assigning the valid_value() return value
87 to a variable, process_error_message() will simply return the
88 error_message. This mode of usage is illustrated by the following example:
89
90 error_message = valid_value(var1)
91
92 This mode is useful for callers who wish to validate a variable and then
93 decide for themselves what to do with the error_message (e.g.
94 raise(error_message), BuiltIn().fail(error_message), etc.).
95
96 If the user of valid_value() is NOT assigning the valid_value() return
97 value to a variable, process_error_message() will behave as follows.
98
99 First, if error_message is non-blank, it will be printed to stderr via a
100 call to gp.print_error_report(error_message).
101
102 If exit_on_error is set:
103 - If the error_message is blank, simply return.
104 - If the error_message is non-blank, exit the program with a return code
105 of 1.
106
107 If exit_on_error is NOT set:
108 - If the error_message is blank, return True.
109 - If the error_message is non-blank, return False.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500110
111 Description of argument(s):
112 error_message An error message.
113 """
114
Michael Walsh018e25f2019-08-01 11:27:12 -0500115 # Determine whether the caller's caller is assigning the result to a
116 # variable.
117 l_value = gp.get_arg_name(None, -1, stack_frame_ix=3)
118 if l_value:
119 return error_message
120
Michael Walshe23b5ad2018-06-01 14:54:35 -0500121 if error_message == "":
Michael Walsh018e25f2019-08-01 11:27:12 -0500122 if exit_on_error:
123 return
Michael Walshe23b5ad2018-06-01 14:54:35 -0500124 return True
125
Michael Walsh018e25f2019-08-01 11:27:12 -0500126 gp.print_error_report(error_message, stack_frame_ix=4)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500127 if exit_on_error:
Michael Walsh10a4d982018-10-30 13:07:46 -0500128 exit(1)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500129 return False
130
Michael Walsh7423c012016-10-04 10:27:21 -0500131
Michael Walsh018e25f2019-08-01 11:27:12 -0500132# Note to programmers: All of the validation functions in this module should
133# follow the same basic template:
134# def valid_value(var_value, var1, var2, varn, *args, **kwargs):
135#
136# error_message = ""
137# if not valid:
138# var_name = get_var_name(*args, **kwargs)
139# error_message += "The following variable is invalid because...:\n"
140# error_message += gp.sprint_varx(var_name, var_value, gp.blank())
141#
142# return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500143
Michael Walsh018e25f2019-08-01 11:27:12 -0500144
145# The docstring header and footer will be added to each validation function's
146# existing docstring.
147docstring_header = \
148 r"""
149 Determine whether var_value is valid, construct an error_message and call
150 process_error_message(error_message).
151
152 See the process_error_message() function defined in this module for a
153 description of how error messages are processed.
Michael Walsh7423c012016-10-04 10:27:21 -0500154 """
155
Michael Walsh018e25f2019-08-01 11:27:12 -0500156additional_args_docstring_footer = \
157 r"""
158 args Additional positional arguments (described
159 below).
160 kwargs Additional keyword arguments (described
161 below).
162
163 Additional argument(s):
164 var_name The name of the variable whose value is
165 passed in var_value. For the general
166 case, this argument is unnecessary as this
167 function can figure out the var_name.
168 This is provided for Robot callers in
169 which case, this function lacks the
170 ability to determine the variable name.
171 """
172
173
174def valid_type(var_value, required_type, *args, **kwargs):
175 r"""
176 The variable value is valid if it is of the required type.
177
178 Examples:
179
180 valid_type(var1, int)
181
182 valid_type(var1, (list, dict))
183
184 Description of argument(s):
185 var_value The value being validated.
186 required_type A type or a tuple of types (e.g. str, int,
187 etc.).
188 """
189
190 error_message = ""
191 if type(required_type) is tuple:
192 if type(var_value) in required_type:
193 return process_error_message(error_message)
194 else:
195 if type(var_value) is required_type:
196 return process_error_message(error_message)
197
198 # If we get to this point, the validation has failed.
199 var_name = get_var_name(*args, **kwargs)
200 error_message += "Invalid variable type:\n"
201 error_message += gp.sprint_varx(var_name, var_value,
202 gp.blank() | gp.show_type())
203 error_message += "\n"
204 error_message += gp.sprint_var(required_type)
205
206 return process_error_message(error_message)
207
208
209def valid_value(var_value, valid_values=[], invalid_values=[], *args,
210 **kwargs):
211
212 r"""
213 The variable value is valid if it is either contained in the valid_values
214 list or if it is NOT contained in the invalid_values list. If the caller
215 specifies nothing for either of these 2 arguments, invalid_values will be
216 initialized to ['', None]. This is a good way to fail on variables which
217 contain blank values.
218
219 It is illegal to specify both valid_values and invalid values.
220
221 Example:
222
223 var1 = ''
224 valid_value(var1)
225
226 This code would fail because var1 is blank and the default value for
227 invalid_values is ['', None].
228
229 Example:
230 var1 = 'yes'
231 valid_value(var1, valid_values=['yes', 'true'])
232
233 This code would pass.
234
235 Description of argument(s):
236 var_value The value being validated.
237 valid_values A list of valid values. The variable
238 value must be equal to one of these values
239 to be considered valid.
240 invalid_values A list of invalid values. If the variable
241 value is equal to any of these, it is
242 considered invalid.
243 """
244
Michael Walshbec416d2016-11-10 08:54:52 -0600245 error_message = ""
Michael Walshbec416d2016-11-10 08:54:52 -0600246
Michael Walshe23b5ad2018-06-01 14:54:35 -0500247 # Validate this function's arguments.
Michael Walsh7423c012016-10-04 10:27:21 -0500248 len_valid_values = len(valid_values)
249 len_invalid_values = len(invalid_values)
250 if len_valid_values > 0 and len_invalid_values > 0:
Michael Walsh018e25f2019-08-01 11:27:12 -0500251 error_message += "Programmer error - You must provide either an"
252 error_message += " invalid_values list or a valid_values"
253 error_message += " list but NOT both:\n"
254 error_message += gp.sprint_var(invalid_values)
255 error_message += gp.sprint_var(valid_values)
256 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500257
258 if len_valid_values > 0:
259 # Processing the valid_values list.
260 if var_value in valid_values:
Michael Walsh018e25f2019-08-01 11:27:12 -0500261 return process_error_message(error_message)
262 var_name = get_var_name(*args, **kwargs)
263 error_message += "Invalid variable value:\n"
264 error_message += gp.sprint_varx(var_name, var_value,
265 gp.blank() | gp.verbose()
266 | gp.show_type())
267 error_message += "\n"
268 error_message += "It must be one of the following values:\n"
269 error_message += "\n"
270 error_message += gp.sprint_var(valid_values,
271 gp.blank() | gp.show_type())
272 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500273
274 if len_invalid_values == 0:
Michael Walshbec416d2016-11-10 08:54:52 -0600275 # Assign default value.
Michael Walsh018e25f2019-08-01 11:27:12 -0500276 invalid_values = ["", None]
Michael Walsh7423c012016-10-04 10:27:21 -0500277
278 # Assertion: We have an invalid_values list. Processing it now.
279 if var_value not in invalid_values:
Michael Walsh018e25f2019-08-01 11:27:12 -0500280 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500281
Michael Walsh018e25f2019-08-01 11:27:12 -0500282 var_name = get_var_name(*args, **kwargs)
283 error_message += "Invalid variable value:\n"
284 error_message += gp.sprint_varx(var_name, var_value,
285 gp.blank() | gp.verbose()
286 | gp.show_type())
287 error_message += "\n"
288 error_message += "It must NOT be one of the following values:\n"
289 error_message += "\n"
290 error_message += gp.sprint_var(invalid_values,
291 gp.blank() | gp.show_type())
Michael Walshe23b5ad2018-06-01 14:54:35 -0500292 return process_error_message(error_message)
Michael Walshbec416d2016-11-10 08:54:52 -0600293
Michael Walshbec416d2016-11-10 08:54:52 -0600294
Michael Walsh018e25f2019-08-01 11:27:12 -0500295def valid_range(var_value, lower=None, upper=None, *args, **kwargs):
Michael Walshbec416d2016-11-10 08:54:52 -0600296 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500297 The variable value is valid if it is within the specified range.
Michael Walshbec416d2016-11-10 08:54:52 -0600298
Michael Walsh018e25f2019-08-01 11:27:12 -0500299 This function can be used with any type of operands where they can have a
300 greater than/less than relationship to each other (e.g. int, float, str).
301
302 Description of argument(s):
Michael Walshbec416d2016-11-10 08:54:52 -0600303 var_value The value being validated.
Michael Walsh018e25f2019-08-01 11:27:12 -0500304 lower The lower end of the range. If not None,
305 the var_value must be greater than or
306 equal to lower.
307 upper The upper end of the range. If not None,
308 the var_value must be less than or equal
309 to upper.
Michael Walshbec416d2016-11-10 08:54:52 -0600310 """
311
Michael Walshbec416d2016-11-10 08:54:52 -0600312 error_message = ""
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500313 if lower is None and upper is None:
Michael Walsh018e25f2019-08-01 11:27:12 -0500314 return process_error_message(error_message)
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500315 if lower is None and var_value <= upper:
Michael Walsh018e25f2019-08-01 11:27:12 -0500316 return process_error_message(error_message)
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500317 if upper is None and var_value >= lower:
Michael Walsh018e25f2019-08-01 11:27:12 -0500318 return process_error_message(error_message)
319 if lower and upper:
320 if lower > upper:
321 var_name = get_var_name(*args, **kwargs)
322 error_message += "Programmer error - the lower value is greater"
323 error_message += " than the upper value:\n"
324 error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type())
325 return process_error_message(error_message)
326 if lower <= var_value <= upper:
327 return process_error_message(error_message)
Michael Walshbec416d2016-11-10 08:54:52 -0600328
Michael Walsh018e25f2019-08-01 11:27:12 -0500329 var_name = get_var_name(*args, **kwargs)
330 error_message += "The following variable is not within the expected"
331 error_message += " range:\n"
332 error_message += gp.sprint_varx(var_name, var_value, gp.show_type())
333 error_message += "\n"
334 error_message += "range:\n"
335 error_message += gp.sprint_vars(lower, upper, fmt=gp.show_type(), indent=2)
Michael Walshe23b5ad2018-06-01 14:54:35 -0500336 return process_error_message(error_message)
Michael Walsh7423c012016-10-04 10:27:21 -0500337
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600338
Michael Walsh018e25f2019-08-01 11:27:12 -0500339def valid_integer(var_value, lower=None, upper=None, *args, **kwargs):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600340 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500341 The variable value is valid if it is an integer or can be interpreted as
342 an integer (e.g. 7, "7", etc.).
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600343
Michael Walsh018e25f2019-08-01 11:27:12 -0500344 This function also calls valid_range to make sure the integer value is
345 within the specified range (if any).
346
347 Description of argument(s):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600348 var_value The value being validated.
Michael Walsh018e25f2019-08-01 11:27:12 -0500349 lower The lower end of the range. If not None,
350 the var_value must be greater than or
351 equal to lower.
352 upper The upper end of the range. If not None,
353 the var_value must be less than or equal
354 to upper.
355 """
356
357 error_message = ""
358 var_name = get_var_name(*args, **kwargs)
359 try:
360 var_value = int(str(var_value), 0)
361 except ValueError:
362 error_message += "Invalid integer value:\n"
363 error_message += gp.sprint_varx(var_name, var_value,
364 gp.blank() | gp.show_type())
365 return process_error_message(error_message)
366
367 # Check the range (if any).
368 if lower:
369 lower = int(str(lower), 0)
370 if upper:
371 upper = int(str(upper), 0)
372 error_message = valid_range(var_value, lower, upper, var_name=var_name)
373
374 return process_error_message(error_message)
375
376
377def valid_dir_path(var_value, *args, **kwargs):
378 r"""
379 The variable value is valid if it contains the path of an existing
380 directory.
381
382 Description of argument(s):
383 var_value The value being validated.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600384 """
385
386 error_message = ""
387 if not os.path.isdir(str(var_value)):
Michael Walsh018e25f2019-08-01 11:27:12 -0500388 var_name = get_var_name(*args, **kwargs)
389 error_message += "The following directory does not exist:\n"
Michael Walsh00244342019-08-29 10:35:50 -0500390 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600391
Michael Walshe23b5ad2018-06-01 14:54:35 -0500392 return process_error_message(error_message)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600393
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600394
Michael Walsh018e25f2019-08-01 11:27:12 -0500395def valid_file_path(var_value, *args, **kwargs):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600396 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500397 The variable value is valid if it contains the path of an existing file.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600398
Michael Walsh018e25f2019-08-01 11:27:12 -0500399 Description of argument(s):
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600400 var_value The value being validated.
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600401 """
402
403 error_message = ""
404 if not os.path.isfile(str(var_value)):
Michael Walsh018e25f2019-08-01 11:27:12 -0500405 var_name = get_var_name(*args, **kwargs)
406 error_message += "The following file does not exist:\n"
Michael Walsh00244342019-08-29 10:35:50 -0500407 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600408
Michael Walshe23b5ad2018-06-01 14:54:35 -0500409 return process_error_message(error_message)
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600410
Michael Walsh78bdfdd2017-01-10 11:27:30 -0600411
Michael Walsh018e25f2019-08-01 11:27:12 -0500412def valid_path(var_value, *args, **kwargs):
Michael Walshe23b5ad2018-06-01 14:54:35 -0500413 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500414 The variable value is valid if it contains the path of an existing file or
415 directory.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500416
Michael Walsh018e25f2019-08-01 11:27:12 -0500417 Description of argument(s):
Michael Walshe23b5ad2018-06-01 14:54:35 -0500418 var_value The value being validated.
Michael Walshe23b5ad2018-06-01 14:54:35 -0500419 """
420
421 error_message = ""
422 if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))):
Michael Walsh018e25f2019-08-01 11:27:12 -0500423 var_name = get_var_name(*args, **kwargs)
424 error_message += "Invalid path (file or directory does not exist):\n"
Michael Walsh00244342019-08-29 10:35:50 -0500425 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walshe23b5ad2018-06-01 14:54:35 -0500426
Michael Walshe23b5ad2018-06-01 14:54:35 -0500427 return process_error_message(error_message)
Michael Walsh2c687e92018-05-09 11:47:56 -0500428
429
Michael Walsh35026be2019-08-14 17:13:39 -0500430def valid_list(var_value, valid_values=[], invalid_values=[],
431 required_values=[], fail_on_empty=False, *args, **kwargs):
Michael Walsh2c687e92018-05-09 11:47:56 -0500432 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500433 The variable value is valid if it is a list where each entry can be found
Michael Walsh35026be2019-08-14 17:13:39 -0500434 in the valid_values list or if none of its values can be found in the
435 invalid_values list or if all of the values in the required_values list
436 can be found in var_value.
437
438 The caller may only specify one of these 3 arguments: valid_values,
439 invalid_values, required_values.
Michael Walsh2c687e92018-05-09 11:47:56 -0500440
Michael Walsh018e25f2019-08-01 11:27:12 -0500441 Description of argument(s):
442 var_value The value being validated.
Michael Walshca193992018-08-02 17:20:00 -0500443 valid_values A list of valid values. Each element in
444 the var_value list must be equal to one of
445 these values to be considered valid.
Michael Walsh35026be2019-08-14 17:13:39 -0500446 invalid_values A list of invalid values. If any element
447 in var_value is equal to any of the values
448 in this argument, var_value is considered
449 invalid.
450 required_values Every value in required_values must be
451 found in var_value. Otherwise, var_value
452 is considered invalid.
Michael Walsh018e25f2019-08-01 11:27:12 -0500453 fail_on_empty Indicates that an empty list for the
454 variable value should be considered an
455 error.
Michael Walshca193992018-08-02 17:20:00 -0500456 """
457
458 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500459
Michael Walsh35026be2019-08-14 17:13:39 -0500460 # Validate this function's arguments.
461 len_valid_values = len(valid_values)
462 len_invalid_values = len(invalid_values)
463 len_required_values = len(required_values)
464 if (len_valid_values + len_invalid_values + len_required_values) > 1:
465 error_message += "Programmer error - You must provide only one of the"
466 error_message += " following: valid_values, invalid_values,"
467 error_message += " required_values.\n"
468 error_message += gp.sprint_var(invalid_values)
469 error_message += gp.sprint_var(valid_values)
470 error_message += gp.sprint_var(required_values)
471 return process_error_message(error_message)
472
Michael Walsh018e25f2019-08-01 11:27:12 -0500473 if type(var_value) is not list:
474 var_name = get_var_name(*args, **kwargs)
475 error_message = valid_type(var_value, list, var_name=var_name)
476 if error_message:
477 return process_error_message(error_message)
478
479 if fail_on_empty and len(var_value) == 0:
480 var_name = get_var_name(*args, **kwargs)
481 error_message += "Invalid empty list:\n"
482 error_message += gp.sprint_varx(var_name, var_value, gp.show_type())
483 return process_error_message(error_message)
Michael Walshca193992018-08-02 17:20:00 -0500484
Michael Walsh35026be2019-08-14 17:13:39 -0500485 if len(required_values):
486 found_error = 0
487 display_required_values = list(required_values)
488 for ix in range(0, len(required_values)):
489 if required_values[ix] not in var_value:
490 found_error = 1
491 display_required_values[ix] = \
492 str(display_required_values[ix]) + "*"
493 if found_error:
494 var_name = get_var_name(*args, **kwargs)
495 error_message += "The following list is invalid:\n"
496 error_message += gp.sprint_varx(var_name, var_value,
497 gp.blank() | gp.show_type())
498 error_message += "\n"
499 error_message += "Because some of the values in the "
500 error_message += "required_values list are not present (see"
501 error_message += " entries marked with \"*\"):\n"
502 error_message += "\n"
503 error_message += gp.sprint_varx('required_values',
504 display_required_values,
505 gp.blank() | gp.show_type())
506 error_message += "\n"
507
508 return process_error_message(error_message)
509
510 if len(invalid_values):
511 found_error = 0
512 display_var_value = list(var_value)
513 for ix in range(0, len(var_value)):
514 if var_value[ix] in invalid_values:
515 found_error = 1
516 display_var_value[ix] = str(var_value[ix]) + "*"
517
518 if found_error:
519 var_name = get_var_name(*args, **kwargs)
520 error_message += "The following list is invalid (see entries"
521 error_message += " marked with \"*\"):\n"
522 error_message += gp.sprint_varx(var_name, display_var_value,
523 gp.blank() | gp.show_type())
524 error_message += "\n"
525 error_message += gp.sprint_var(invalid_values, gp.show_type())
526 return process_error_message(error_message)
527
Michael Walshca193992018-08-02 17:20:00 -0500528 found_error = 0
529 display_var_value = list(var_value)
530 for ix in range(0, len(var_value)):
531 if var_value[ix] not in valid_values:
532 found_error = 1
Michael Walsh35026be2019-08-14 17:13:39 -0500533 display_var_value[ix] = str(var_value[ix]) + "*"
Michael Walshca193992018-08-02 17:20:00 -0500534
535 if found_error:
Michael Walsh018e25f2019-08-01 11:27:12 -0500536 var_name = get_var_name(*args, **kwargs)
537 error_message += "The following list is invalid (see entries marked"
538 error_message += " with \"*\"):\n"
539 error_message += gp.sprint_varx(var_name, display_var_value,
540 gp.blank() | gp.show_type())
541 error_message += "\n"
Michael Walsh35026be2019-08-14 17:13:39 -0500542 error_message += gp.sprint_var(valid_values, gp.show_type())
Michael Walsh018e25f2019-08-01 11:27:12 -0500543 return process_error_message(error_message)
Michael Walshca193992018-08-02 17:20:00 -0500544
Michael Walshca193992018-08-02 17:20:00 -0500545 return process_error_message(error_message)
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500546
547
Michael Walsh018e25f2019-08-01 11:27:12 -0500548def valid_dict(var_value, required_keys=[], *args, **kwargs):
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500549 r"""
Michael Walsh018e25f2019-08-01 11:27:12 -0500550 The variable value is valid if it is a dictionary containing all of the
551 required keys.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500552
Michael Walsh018e25f2019-08-01 11:27:12 -0500553 Description of argument(s):
554 var_value The value being validated.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500555 required_keys A list of keys which must be found in the
556 dictionary for it to be considered valid.
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500557 """
558
559 error_message = ""
Michael Walsh018e25f2019-08-01 11:27:12 -0500560 missing_keys = list(set(required_keys) - set(var_value.keys()))
561 if len(missing_keys) > 0:
562 var_name = get_var_name(*args, **kwargs)
563 error_message += "The following dictionary is invalid because it is"
564 error_message += " missing required keys:\n"
565 error_message += gp.sprint_varx(var_name, var_value,
566 gp.blank() | gp.show_type())
567 error_message += "\n"
Michael Walsh35026be2019-08-14 17:13:39 -0500568 error_message += gp.sprint_var(missing_keys, gp.show_type())
Michael Walsh7ac5fd82018-10-11 16:58:49 -0500569 return process_error_message(error_message)
Michael Walsh018e25f2019-08-01 11:27:12 -0500570
571
Michael Walshbe3a8152019-08-20 16:38:19 -0500572def valid_program(var_value, *args, **kwargs):
573 r"""
574 The variable value is valid if it contains the name of a program which can
575 be located using the "which" command.
576
577 Description of argument(s):
578 var_value The value being validated.
579 """
580
581 error_message = ""
582 rc, out_buf = gc.shell_cmd("which " + var_value, quiet=1, show_err=0,
583 ignore_err=1)
584 if rc:
585 var_name = get_var_name(*args, **kwargs)
586 error_message += "The following required program could not be found"
587 error_message += " using the $PATH environment variable:\n"
Michael Walsh00244342019-08-29 10:35:50 -0500588 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
Michael Walshbe3a8152019-08-20 16:38:19 -0500589 PATH = os.environ.get("PATH", "").split(":")
590 error_message += "\n"
591 error_message += gp.sprint_var(PATH)
592 return process_error_message(error_message)
593
594
Michael Walshb9d8dfd2019-09-11 11:11:12 -0500595def valid_length(var_value, min_length=None, max_length=None, *args, **kwargs):
596 r"""
597 The variable value is valid if it is an object (e.g. list, dictionary)
598 whose length is within the specified range.
599
600 Description of argument(s):
601 var_value The value being validated.
602 min_length The minimum length of the object. If not
603 None, the length of var_value must be
604 greater than or equal to min_length.
605 max_length The maximum length of the object. If not
606 None, the length of var_value must be less
607 than or equal to min_length.
608 """
609
610 error_message = ""
611 length = len(var_value)
612 error_message = valid_range(length, min_length, max_length)
613 if error_message:
614 var_name = get_var_name(*args, **kwargs)
615 error_message = "The length of the following object is not within the"
616 error_message += " expected range:\n"
617 error_message += gp.sprint_var(length)
618 error_message += gp.sprint_varx(var_name, var_value, gp.blank())
619 error_message += "\n"
620 error_message += gp.sprint_vars(min_length, max_length)
621 return process_error_message(error_message)
622
623 return process_error_message(error_message)
624
625
Michael Walsh018e25f2019-08-01 11:27:12 -0500626# Modify selected function docstrings by adding headers/footers.
627
628func_names = [
629 "valid_type", "valid_value", "valid_range", "valid_integer",
630 "valid_dir_path", "valid_file_path", "valid_path", "valid_list",
Michael Walshbe3a8152019-08-20 16:38:19 -0500631 "valid_dict", "valid_program"
Michael Walsh018e25f2019-08-01 11:27:12 -0500632]
633
634raw_doc_strings = {}
635
636for func_name in func_names:
637 cmd_buf = "raw_doc_strings['" + func_name + "'] = " + func_name
638 cmd_buf += ".__doc__"
639 exec(cmd_buf)
640 cmd_buf = func_name + ".__doc__ = docstring_header + " + func_name
641 cmd_buf += ".__doc__.rstrip(\" \\n\") + additional_args_docstring_footer"
642 exec(cmd_buf)