1#!/usr/bin/env python 2 3r""" 4This module provides valuable argument processing functions like 5gen_get_options and sprint_args. 6""" 7 8import os 9import gen_print as gp 10 11exit_on_error = False 12 13 14def set_exit_on_error(value): 15 r""" 16 Set the exit_on_error value to either True or False. 17 18 If exit_on_error is set, validation functions like valid_value will exit 19 the program on error instead of returning False. 20 21 Description of argument(s): 22 value Value to set global exit_on_error to. 23 """ 24 25 global exit_on_error 26 exit_on_error = value 27 28 29def get_var_name(var_name): 30 r""" 31 If var_name has a value, simply return it. Otherwise, get the variable 32 name of the first argument used to call the validation function (e.g. 33 valid_value, valid_integer, etc.) and return it. 34 35 This function is designed solely for use by other functions in this file. 36 37 Example: 38 39 A programmer codes this: 40 41 valid_value(last_name) 42 43 Which results in the following call stack: 44 45 valid_value(last_name) 46 -> svalid_value(var_value...) 47 -> get_var_name(var_name) 48 49 In this example, this function will return "last_name". 50 51 Example: 52 53 err_msg = svalid_value(last_name, var_name="some_other_name") 54 55 Which results in the following call stack: 56 57 svalid_value(var_value, var_name="some_other_name") 58 -> get_var_name(var_name) 59 60 In this example, this function will return "some_other_name". 61 62 Description of argument(s): 63 var_name The name of the variable. 64 """ 65 66 if var_name != "": 67 return var_name 68 # Calculate stack_frame_ix. The validation functions in this file come 69 # in pairs. There is an "s" version of each validation function (e.g. 70 # svalid_value) whose job is to return an error message string. Then 71 # there is a wrapper function (e.g. valid_value) that will call the "s" 72 # version and print the result if there is an error. See examples 1 and 2 73 # above for illustration. This function must be cognizant of both 74 # scenarios to accurately determine the name of the variable being 75 # validated. Where the "s" function is being called directly, the 76 # stack_frame_ix should be set to 3. Where the wrapper function is being 77 # called, the stack_frame_ix should be incremented to 4. 78 stack_frame_ix = 3 79 parent_func_name = gp.sprint_func_name(2) 80 grandparent_func_name = gp.sprint_func_name(3) 81 if parent_func_name == "s" + grandparent_func_name: 82 stack_frame_ix += 1 83 var_name = gp.get_arg_name(0, 1, stack_frame_ix) 84 return var_name 85 86 87def process_error_message(error_message): 88 r""" 89 Process the error_message as follows: 90 - If the error_message is blank, return True. 91 - If the error_message contains a value: 92 - Print the error_message as part of a full error report. 93 - If global exit_on_error is set, then exit the program with a return 94 code of 1. 95 - If exit_on_error is not set, return False. 96 97 This function is designed solely for use by wrapper functions in this file 98 (e.g. "valid_value"). 99 100 Description of argument(s): 101 error_message An error message. 102 """ 103 104 if error_message == "": 105 return True 106 107 gp.print_error_report(error_message) 108 if exit_on_error: 109 exit(1) 110 return False 111 112 113def svalid_value(var_value, 114 invalid_values=[], 115 valid_values=[], 116 var_name=""): 117 r""" 118 Return an empty string if var_value is a valid value. Otherwise, return 119 an error string. 120 121 Description of arguments: 122 var_value The value being validated. 123 invalid_values A list of invalid values. If var_value is 124 equal to any of these, it is invalid. 125 Note that if you specify anything for 126 invalid_values (below), the valid_values 127 list is not even processed. If you 128 specify nothing for both invalid_values 129 and valid_values, invalid_values will be 130 set to a default value of [""]. 131 valid_values A list of valid values. var_value must be 132 equal to one of these values to be 133 considered valid. 134 var_name The name of the variable whose value is 135 passed in var_value. This parameter is 136 normally unnecessary as this function can 137 figure out the var_name. This is provided 138 for Robot callers. In this scenario, we 139 are unable to get the variable name 140 ourselves. 141 """ 142 143 success_message = "" 144 error_message = "" 145 146 # Validate this function's arguments. 147 len_valid_values = len(valid_values) 148 len_invalid_values = len(invalid_values) 149 if len_valid_values > 0 and len_invalid_values > 0: 150 error_message += "Programmer error - You must provide either an" +\ 151 " invalid_values list or a valid_values" +\ 152 " list but NOT both.\n" +\ 153 gp.sprint_var(invalid_values) +\ 154 gp.sprint_var(valid_values) 155 return error_message 156 157 show_blanks = 1 158 if len_valid_values > 0: 159 # Processing the valid_values list. 160 if var_value in valid_values: 161 return success_message 162 error_message += "The following variable has an invalid" +\ 163 " value:\n" +\ 164 gp.sprint_varx(get_var_name(var_name), var_value, 165 show_blanks) +\ 166 "\nIt must be one of the following values:\n" +\ 167 gp.sprint_varx("valid_values", valid_values, 168 show_blanks) 169 return error_message 170 171 if len_invalid_values == 0: 172 # Assign default value. 173 invalid_values = [""] 174 175 # Assertion: We have an invalid_values list. Processing it now. 176 if var_value not in invalid_values: 177 return success_message 178 179 error_message += "The following variable has an invalid value:\n" +\ 180 gp.sprint_varx(get_var_name(var_name), var_value, 181 show_blanks) +\ 182 "\nIt must NOT be one of the following values:\n" +\ 183 gp.sprint_varx("invalid_values", invalid_values, 184 show_blanks) 185 return error_message 186 187 188def valid_value(var_value, 189 invalid_values=[], 190 valid_values=[], 191 var_name=""): 192 r""" 193 Return True if var_value is valid. Otherwise, print an error message and 194 either return False or exit(1) depending on the value of exit_on_error. 195 196 Description of arguments: 197 (See description of arguments for svalid_value (above)). 198 """ 199 200 error_message = svalid_value(var_value, invalid_values, valid_values, 201 var_name) 202 return process_error_message(error_message) 203 204 205def svalid_integer(var_value, 206 var_name=""): 207 r""" 208 Return an empty string if var_value is a valid integer. Otherwise, return 209 an error string. 210 211 Description of arguments: 212 var_value The value being validated. 213 var_name The name of the variable whose value is 214 passed in var_value. This parameter is 215 normally unnecessary as this function can 216 figure out the var_name. This is provided 217 for Robot callers. In this scenario, we 218 are unable to get the variable name 219 ourselves. 220 """ 221 222 success_message = "" 223 error_message = "" 224 try: 225 if isinstance(int(str(var_value), 0), int): 226 return success_message 227 except ValueError: 228 pass 229 230 # If we get to this point, the validation has failed. 231 show_blanks = 1 232 error_message +=\ 233 "Invalid integer value:\n" +\ 234 gp.sprint_varx(get_var_name(var_name), var_value, show_blanks) 235 236 return error_message 237 238 239def valid_integer(var_value, 240 var_name=""): 241 r""" 242 Return True if var_value is a valid integer. Otherwise, print an error 243 message and either return False or exit(1) depending on the value of 244 exit_on_error. 245 246 Description of arguments: 247 (See description of arguments for svalid_integer (above)). 248 """ 249 250 error_message = svalid_integer(var_value, var_name) 251 return process_error_message(error_message) 252 253 254def svalid_dir_path(var_value, 255 var_name=""): 256 r""" 257 Return an empty string if var_value is a valid directory path. Otherwise, 258 return an error string. 259 260 Description of arguments: 261 var_value The value being validated. 262 var_name The name of the variable whose value is 263 passed in var_value. This parameter is 264 normally unnecessary as this function can 265 figure out the var_name. This is provided 266 for Robot callers. In this scenario, we 267 are unable to get the variable name 268 ourselves. 269 """ 270 271 error_message = "" 272 if not os.path.isdir(str(var_value)): 273 error_message += "The following directory does not exist:\n" +\ 274 gp.sprint_varx(get_var_name(var_name), var_value) 275 276 return error_message 277 278 279def valid_dir_path(var_value, 280 var_name=""): 281 r""" 282 Return True if var_value is a valid directory path. Otherwise, print an 283 error message and either return False or exit(1) depending on the value of 284 exit_on_error. 285 286 Valid means that the directory path exists. 287 288 Description of arguments: 289 (See description of arguments for svalid_dir_path (above)). 290 """ 291 292 error_message = svalid_dir_path(var_value, var_name) 293 return process_error_message(error_message) 294 295 296def svalid_file_path(var_value, 297 var_name=""): 298 r""" 299 Return an empty string if var_value is a valid file path. Otherwise, 300 return an error string. 301 302 Description of arguments: 303 var_value The value being validated. 304 var_name The name of the variable whose value is 305 passed in var_value. This parameter is 306 normally unnecessary as this function can 307 figure out the var_name. This is provided 308 for Robot callers. In this scenario, we 309 are unable to get the variable name 310 ourselves. 311 """ 312 313 error_message = "" 314 if not os.path.isfile(str(var_value)): 315 error_message += "Invalid file (does not exist):\n" +\ 316 gp.sprint_varx(get_var_name(var_name), var_value) 317 318 return error_message 319 320 321def valid_file_path(var_value, 322 var_name=""): 323 r""" 324 Return True if var_value is a valid file path. Otherwise, print an error 325 message and either return False or exit(1) depending on the value of 326 exit_on_error. 327 328 Valid means that the file exists. 329 330 Description of arguments: 331 (See description of arguments for svalid_file_path (above)). 332 """ 333 334 error_message = svalid_file_path(var_value, var_name) 335 return process_error_message(error_message) 336 337 338def svalid_path(var_value, 339 var_name=""): 340 r""" 341 Return an empty string if var_value is either a valid file path or 342 directory path. Otherwise, return an error string. 343 344 Description of arguments: 345 var_value The value being validated. 346 var_name The name of the variable whose value is 347 passed in var_value. This parameter is 348 normally unnecessary as this function can 349 figure out the var_name. This is provided 350 for Robot callers. In this scenario, we 351 are unable to get the variable name 352 ourselves. 353 """ 354 355 error_message = "" 356 if not (os.path.isfile(str(var_value)) or os.path.isdir(str(var_value))): 357 error_message = "Invalid path (file or directory does not exist):\n" +\ 358 gp.sprint_varx(get_var_name(var_name), var_value) 359 360 return error_message 361 362 363def valid_path(var_value, 364 var_name=""): 365 r""" 366 Return True if var_value is a valid file path. Otherwise, print an error 367 message and either return False or exit(1) depending on the value of 368 exit_on_error. 369 370 Valid means that the file exists. 371 372 Description of arguments: 373 (See description of arguments for svalid_path (above)). 374 """ 375 376 error_message = svalid_path(var_value, var_name) 377 return process_error_message(error_message) 378 379 380def svalid_range(var_value, 381 valid_range=[], 382 var_name=""): 383 r""" 384 Return an empty string if var_value is within the range. Otherwise, 385 return an error string. 386 387 Description of arguments: 388 var_value The value being validated. This value 389 must be an integer. 390 valid_range A list comprised of one or two elements 391 which are the lower and upper ends of a 392 range. These values must be integers 393 except where noted. Valid specifications 394 may be of the following forms: [lower, 395 upper], [lower] or [None, upper]. 396 var_name The name of the variable whose value is 397 passed in var_value. This parameter is 398 normally unnecessary as this function can 399 figure out the var_name. This is provided 400 for Robot callers. In this scenario, we 401 are unable to get the variable name 402 ourselves. 403 """ 404 405 error_message = "" 406 407 # Validate this function's parms: 408 # First, ensure that the value is an integer. 409 error_message = svalid_integer(var_value, var_name) 410 if not error_message == "": 411 return error_message 412 var_value = int(var_value) 413 414 len_valid_range = len(valid_range) 415 if len_valid_range == 0 or len_valid_range > 2: 416 error_message += "Programmer error - For the valid_range parameter," +\ 417 " you must provide a list consisting of one or two" +\ 418 " elements.\n" +\ 419 gp.sprint_var(valid_range) 420 return error_message 421 422 if len_valid_range == 1 or valid_range[0] is not None: 423 # Make sure lower valid_range value is an integer. 424 error_message = svalid_integer(valid_range[0], "valid_range[0]") 425 if not error_message == "": 426 error_message = "Programmer error:\n" + error_message 427 return error_message 428 if valid_range[0] is not None: 429 valid_range[0] = int(valid_range[0]) 430 if len_valid_range == 2: 431 # Make sure upper valid_range value is an integer. 432 error_message = svalid_integer(valid_range[1], "valid_range[1]") 433 if not error_message == "": 434 error_message = "Programmer error:\n" + error_message 435 return error_message 436 valid_range[1] = int(valid_range[1]) 437 if valid_range[0] is not None and valid_range[0] > valid_range[1]: 438 error_message = "Programmer error - In the following range, the" +\ 439 " lower limit is greater than the upper" +\ 440 " limit:\n" + gp.sprint_varx("valid_range", 441 valid_range) 442 return error_message 443 444 if len_valid_range == 1: 445 if var_value < valid_range[0]: 446 error_message += "The following variable is not within the" +\ 447 " expected range:\n" +\ 448 gp.sprint_varx(get_var_name(var_name), 449 var_value) +\ 450 gp.sprint_varx("valid_range", 451 str(valid_range[0]) + "..") 452 return error_message 453 return error_message 454 455 if valid_range[0] is None: 456 if var_value > valid_range[1]: 457 error_message += "The following variable is not within the" +\ 458 " expected range:\n" +\ 459 gp.sprint_varx(get_var_name(var_name), 460 var_value) +\ 461 gp.sprint_varx("valid_range", 462 ".." + str(valid_range[1])) 463 return error_message 464 465 if var_value < valid_range[0] or var_value > valid_range[1]: 466 error_message += "The following variable is not within the expected" +\ 467 " range:\n" +\ 468 gp.sprint_varx(get_var_name(var_name), var_value) +\ 469 gp.sprint_varx("valid_range", 470 str(valid_range[0]) + ".." 471 + str(valid_range[1])) 472 return error_message 473 474 return error_message 475 476 477def valid_range(var_value, 478 valid_range=[], 479 var_name=""): 480 r""" 481 Return True if var_value is within range. Otherwise, print an error 482 message and either return False or exit(1) depending on the value of 483 exit_on_error. 484 485 Description of arguments: 486 (See description of arguments for svalid_range (above)). 487 """ 488 489 error_message = svalid_range(var_value, valid_range, var_name) 490 return process_error_message(error_message) 491 492 493def svalid_list(var_value, 494 valid_values=[], 495 var_name=""): 496 r""" 497 Return an empty string if var_value is a valid list. Otherwise, return an 498 error string. 499 500 Description of arguments: 501 var_value The value (i.e. list) being validated. 502 valid_values A list of valid values. Each element in 503 the var_value list must be equal to one of 504 these values to be considered valid. 505 var_name The name of the variable whose value is 506 passed in var_value. This parameter is 507 normally unnecessary as this function can 508 figure out the var_name. This is provided 509 for Robot callers. In this scenario, we 510 are unable to get the variable name 511 ourselves. 512 """ 513 514 error_message = "" 515 if len(var_value) == 0: 516 show_blanks = 1 517 error_message += "The \"" + get_var_name(var_name) 518 error_message += "\" list is empty and is therefore invalid:\n" 519 return error_message 520 521 found_error = 0 522 display_var_value = list(var_value) 523 for ix in range(0, len(var_value)): 524 if var_value[ix] not in valid_values: 525 found_error = 1 526 display_var_value[ix] = var_value[ix] + "*" 527 528 if found_error: 529 show_blanks = 1 530 error_message += "The list entries marked with \"*\" are not valid:\n" 531 error_message += gp.sprint_varx(get_var_name(var_name), 532 display_var_value, show_blanks) 533 error_message += gp.sprint_var(valid_values) 534 return error_message 535 536 return "" 537 538 539def valid_list(var_value, 540 valid_values=[], 541 var_name=""): 542 r""" 543 Return True if var_value is a valid list. Otherwise, print an error 544 message and either return False or exit(1) depending on the value of 545 exit_on_error. 546 547 Description of arguments: 548 (See description of arguments for svalid_list (above)). 549 """ 550 551 error_message = svalid_list(var_value, valid_values, var_name) 552 return process_error_message(error_message) 553 554 555def svalid_dict(var_value, 556 required_keys=[], 557 var_name=""): 558 r""" 559 Return an empty string if var_value is a valid dictionary. Otherwise, 560 return an error string. 561 562 Description of arguments: 563 var_value The value (i.e. dictionary) being 564 validated. 565 required_keys A list of keys which must be found in the 566 dictionary for it to be considered valid. 567 var_name The name of the variable whose value is 568 passed in var_value. This parameter is 569 normally unnecessary as this function can 570 figure out the var_name. This is provided 571 for Robot callers. In this scenario, we 572 are unable to get the variable name 573 ourselves. 574 """ 575 576 error_message = "" 577 578 keys_missing = list(set(required_keys) - set(var_value.keys())) 579 if len(keys_missing) > 0: 580 show_blanks = 1 581 var_name = get_var_name(var_name) 582 error_message = "The following key fields are missing from " 583 error_message += var_name + ":\n" 584 error_message += gp.sprint_var(keys_missing) 585 error_message += gp.sprint_varx(var_name, var_value, show_blanks) 586 return error_message 587 588 return "" 589 590 591def valid_dict(var_value, 592 required_keys=[], 593 var_name=""): 594 r""" 595 Return True if var_value is a valid dictionary. Otherwise, print an error 596 message and either return False or exit(1) depending on the value of 597 exit_on_error. 598 599 Description of arguments: 600 (See description of arguments for svalid_list (above)). 601 """ 602 603 error_message = svalid_dict(var_value, required_keys, var_name) 604 return process_error_message(error_message) 605