1#!/usr/bin/env python 2 3r""" 4This module provides many print functions such as sprint_var, sprint_time, 5sprint_error, sprint_call_stack. 6""" 7 8import sys 9import os 10import time 11import inspect 12import re 13import grp 14import socket 15import argparse 16import copy 17try: 18 import __builtin__ 19except ImportError: 20 import builtins as __builtin__ 21import logging 22import collections 23from wrap_utils import * 24 25try: 26 robot_env = 1 27 from robot.utils import DotDict 28 from robot.utils import NormalizedDict 29 from robot.libraries.BuiltIn import BuiltIn 30 # Having access to the robot libraries alone does not indicate that we 31 # are in a robot environment. The following try block should confirm that. 32 try: 33 var_value = BuiltIn().get_variable_value("${SUITE_NAME}", "") 34 except BaseException: 35 robot_env = 0 36except ImportError: 37 robot_env = 0 38 39import gen_arg as ga 40 41# Setting these variables for use both inside this module and by programs 42# importing this module. 43pgm_file_path = sys.argv[0] 44pgm_name = os.path.basename(pgm_file_path) 45pgm_dir_path = os.path.normpath(re.sub("/" + pgm_name, "", pgm_file_path)) +\ 46 os.path.sep 47 48 49# Some functions (e.g. sprint_pgm_header) have need of a program name value 50# that looks more like a valid variable name. Therefore, we'll swap odd 51# characters like "." out for underscores. 52pgm_name_var_name = pgm_name.replace(".", "_") 53 54# Initialize global values used as defaults by print_time, print_var, etc. 55dft_indent = 0 56 57# Calculate default column width for print_var functions based on environment 58# variable settings. The objective is to make the variable values line up 59# nicely with the time stamps. 60dft_col1_width = 29 61 62NANOSECONDS = os.environ.get('NANOSECONDS', '1') 63 64if NANOSECONDS == "1": 65 dft_col1_width = dft_col1_width + 7 66 67SHOW_ELAPSED_TIME = os.environ.get('SHOW_ELAPSED_TIME', '1') 68 69if SHOW_ELAPSED_TIME == "1": 70 if NANOSECONDS == "1": 71 dft_col1_width = dft_col1_width + 14 72 else: 73 dft_col1_width = dft_col1_width + 7 74 75# Initialize some time variables used in module functions. 76start_time = time.time() 77# sprint_time_last_seconds is used to calculate elapsed seconds. 78sprint_time_last_seconds = [start_time, start_time] 79# Define global index for the sprint_time_last_seconds list. 80last_seconds_ix = 0 81 82 83def set_last_seconds_ix(ix): 84 r""" 85 Set the "last_seconds_ix" module variable to the index value. 86 87 Description of argument(s): 88 ix The index value to be set into the module 89 global last_seconds_ix variable. 90 """ 91 global last_seconds_ix 92 last_seconds_ix = ix 93 94 95# Since output from the lprint_ functions goes to a different location than 96# the output from the print_ functions (e.g. a file vs. the console), 97# sprint_time_last_seconds has been created as a list rather than a simple 98# integer so that it can store multiple sprint_time_last_seconds values. 99# Standard print_ functions defined in this file will use 100# sprint_time_last_seconds[0] and the lprint_ functions will use 101# sprint_time_last_seconds[1]. 102def standard_print_last_seconds_ix(): 103 r""" 104 Return the standard print last_seconds index value to the caller. 105 """ 106 return 0 107 108 109def lprint_last_seconds_ix(): 110 r""" 111 Return lprint last_seconds index value to the caller. 112 """ 113 return 1 114 115 116# The user can set environment variable "GEN_PRINT_DEBUG" to get debug output 117# from this module. 118gen_print_debug = int(os.environ.get('GEN_PRINT_DEBUG', 0)) 119 120 121def sprint_func_name(stack_frame_ix=None): 122 r""" 123 Return the function name associated with the indicated stack frame. 124 125 Description of argument(s): 126 stack_frame_ix The index of the stack frame whose 127 function name should be returned. If the 128 caller does not specify a value, this 129 function will set the value to 1 which is 130 the index of the caller's stack frame. If 131 the caller is the wrapper function 132 "print_func_name", this function will bump 133 it up by 1. 134 """ 135 136 # If user specified no stack_frame_ix, we'll set it to a proper default 137 # value. 138 if stack_frame_ix is None: 139 func_name = sys._getframe().f_code.co_name 140 caller_func_name = sys._getframe(1).f_code.co_name 141 if func_name[1:] == caller_func_name: 142 stack_frame_ix = 2 143 else: 144 stack_frame_ix = 1 145 146 func_name = sys._getframe(stack_frame_ix).f_code.co_name 147 148 return func_name 149 150 151def work_around_inspect_stack_cwd_failure(): 152 r""" 153 Work around the inspect.stack() getcwd() failure by making "/tmp" the 154 current working directory. 155 156 NOTES: If the current working directory has been deleted, inspect.stack() 157 will fail with "OSError: [Errno 2] No such file or directory" because it 158 tries to do a getcwd(). 159 160 This function will try to prevent this failure by detecting the scenario 161 in advance and making "/tmp" the current working directory. 162 """ 163 try: 164 os.getcwd() 165 except OSError: 166 os.chdir("/tmp") 167 168 169def get_line_indent(line): 170 r""" 171 Return the number of spaces at the beginning of the line. 172 """ 173 174 return len(line) - len(line.lstrip(' ')) 175 176 177# get_arg_name is not a print function per se. It has been included in this 178# module because it is used by sprint_var which is defined in this module. 179def get_arg_name(var, 180 arg_num=1, 181 stack_frame_ix=1): 182 r""" 183 Return the "name" of an argument passed to a function. This could be a 184 literal or a variable name. 185 186 Description of argument(s): 187 var The variable whose name is to be returned. 188 arg_num The arg number whose name is to be 189 returned. To illustrate how arg_num is 190 processed, suppose that a programmer codes 191 this line: "rc, outbuf = my_func(var1, 192 var2)" and suppose that my_func has this 193 line of code: "result = gp.get_arg_name(0, 194 arg_num, 2)". If arg_num is positive, the 195 indicated argument is returned. For 196 example, if arg_num is 1, "var1" would be 197 returned, If arg_num is 2, "var2" would be 198 returned. If arg_num exceeds the number 199 of arguments, get_arg_name will simply 200 return a complete list of the arguments. 201 If arg_num is 0, get_arg_name will return 202 the name of the target function as 203 specified in the calling line ("my_func" 204 in this case). To clarify, if the caller 205 of the target function uses an alias 206 function name, the alias name would be 207 returned. If arg_num is negative, an 208 lvalue variable name is returned. 209 Continuing with the given example, if 210 arg_num is -2 the 2nd parm to the left of 211 the "=" ("rc" in this case) should be 212 returned. If arg_num is -1, the 1st parm 213 to the left of the "=" ("out_buf" in this 214 case) should be returned. If arg_num is 215 less than -2, an entire dictionary is 216 returned. The keys to the dictionary for 217 this example would be -2 and -1. 218 stack_frame_ix The stack frame index of the target 219 function. This value must be 1 or 220 greater. 1 would indicate get_arg_name's 221 stack frame. 2 would be the caller of 222 get_arg_name's stack frame, etc. 223 224 Example 1: 225 226 my_var = "mike" 227 var_name = get_arg_name(my_var) 228 229 In this example, var_name will receive the value "my_var". 230 231 Example 2: 232 233 def test1(var): 234 # Getting the var name of the first arg to this function, test1. 235 # Note, in this case, it doesn't matter what is passed as the first 236 # arg to get_arg_name since it is the caller's variable name that 237 # matters. 238 dummy = 1 239 arg_num = 1 240 stack_frame = 2 241 var_name = get_arg_name(dummy, arg_num, stack_frame) 242 243 # Mainline... 244 245 another_var = "whatever" 246 test1(another_var) 247 248 In this example, var_name will be set to "another_var". 249 250 """ 251 252 # Note: To avoid infinite recursion, avoid calling any function that 253 # calls this function (e.g. sprint_var, valid_value, etc.). 254 255 # The user can set environment variable "GET_ARG_NAME_DEBUG" to get debug 256 # output from this function. 257 local_debug = int(os.environ.get('GET_ARG_NAME_DEBUG', 0)) 258 # In addition to GET_ARG_NAME_DEBUG, the user can set environment 259 # variable "GET_ARG_NAME_SHOW_SOURCE" to have this function include source 260 # code in the debug output. 261 local_debug_show_source = int( 262 os.environ.get('GET_ARG_NAME_SHOW_SOURCE', 0)) 263 264 if stack_frame_ix < 1: 265 print_error("Programmer error - Variable \"stack_frame_ix\" has an" 266 + " invalid value of \"" + str(stack_frame_ix) + "\". The" 267 + " value must be an integer that is greater than or equal" 268 + " to 1.\n") 269 return 270 271 if local_debug: 272 debug_indent = 2 273 print("") 274 print_dashes(0, 120) 275 print(sprint_func_name() + "() parms:") 276 print_varx("var", var, indent=debug_indent) 277 print_varx("arg_num", arg_num, indent=debug_indent) 278 print_varx("stack_frame_ix", stack_frame_ix, indent=debug_indent) 279 print("") 280 print_call_stack(debug_indent, 2) 281 282 work_around_inspect_stack_cwd_failure() 283 for count in range(0, 2): 284 try: 285 frame, filename, cur_line_no, function_name, lines, index = \ 286 inspect.stack()[stack_frame_ix] 287 except IndexError: 288 print_error("Programmer error - The caller has asked for" 289 + " information about the stack frame at index \"" 290 + str(stack_frame_ix) + "\". However, the stack" 291 + " only contains " + str(len(inspect.stack())) 292 + " entries. Therefore the stack frame index is out" 293 + " of range.\n") 294 return 295 if filename != "<string>": 296 break 297 # filename of "<string>" may mean that the function in question was 298 # defined dynamically and therefore its code stack is inaccessible. 299 # This may happen with functions like "rqprint_var". In this case, 300 # we'll increment the stack_frame_ix and try again. 301 stack_frame_ix += 1 302 if local_debug: 303 print("Adjusted stack_frame_ix...") 304 print_varx("stack_frame_ix", stack_frame_ix, indent=debug_indent) 305 306 real_called_func_name = sprint_func_name(stack_frame_ix) 307 308 module = inspect.getmodule(frame) 309 310 # Though one would expect inspect.getsourcelines(frame) to get all module 311 # source lines if the frame is "<module>", it doesn't do that. Therefore, 312 # for this special case, do inspect.getsourcelines(module). 313 if function_name == "<module>": 314 source_lines, source_line_num =\ 315 inspect.getsourcelines(module) 316 line_ix = cur_line_no - source_line_num - 1 317 else: 318 source_lines, source_line_num =\ 319 inspect.getsourcelines(frame) 320 line_ix = cur_line_no - source_line_num 321 322 if local_debug: 323 print("\n Variables retrieved from inspect.stack() function:") 324 print_varx("frame", frame, indent=debug_indent + 2) 325 print_varx("filename", filename, indent=debug_indent + 2) 326 print_varx("cur_line_no", cur_line_no, indent=debug_indent + 2) 327 print_varx("function_name", function_name, indent=debug_indent + 2) 328 print_varx("lines", lines, indent=debug_indent + 2) 329 print_varx("index", index, indent=debug_indent + 2) 330 print_varx("source_line_num", source_line_num, indent=debug_indent) 331 print_varx("line_ix", line_ix, indent=debug_indent) 332 if local_debug_show_source: 333 print_varx("source_lines", source_lines, indent=debug_indent) 334 print_varx("real_called_func_name", real_called_func_name, 335 indent=debug_indent) 336 337 # Get a list of all functions defined for the module. Note that this 338 # doesn't work consistently when _run_exitfuncs is at the top of the stack 339 # (i.e. if we're running an exit function). I've coded a work-around 340 # below for this deficiency. 341 all_functions = inspect.getmembers(module, inspect.isfunction) 342 343 # Get called_func_id by searching for our function in the list of all 344 # functions. 345 called_func_id = None 346 for func_name, function in all_functions: 347 if func_name == real_called_func_name: 348 called_func_id = id(function) 349 break 350 # NOTE: The only time I've found that called_func_id can't be found is 351 # when we're running from an exit function. 352 353 # Look for other functions in module with matching id. 354 aliases = set([real_called_func_name]) 355 for func_name, function in all_functions: 356 if func_name == real_called_func_name: 357 continue 358 func_id = id(function) 359 if func_id == called_func_id: 360 aliases.add(func_name) 361 362 # In most cases, my general purpose code above will find all aliases. 363 # However, for the odd case (i.e. running from exit function), I've added 364 # code to handle pvar, qpvar, dpvar, etc. aliases explicitly since they 365 # are defined in this module and used frequently. 366 # pvar is an alias for print_var. 367 aliases.add(re.sub("print_var", "pvar", real_called_func_name)) 368 369 # The call to the function could be encased in a recast (e.g. 370 # int(func_name())). 371 recast_regex = "([^ ]+\\([ ]*)?" 372 import_name_regex = "([a-zA-Z0-9_]+\\.)?" 373 func_name_regex = recast_regex + import_name_regex + "(" +\ 374 '|'.join(aliases) + ")" 375 pre_args_regex = ".*" + func_name_regex + "[ ]*\\(" 376 377 # Search backward through source lines looking for the calling function 378 # name. 379 found = False 380 for start_line_ix in range(line_ix, 0, -1): 381 # Skip comment lines. 382 if re.match(r"[ ]*#", source_lines[start_line_ix]): 383 continue 384 if re.match(pre_args_regex, source_lines[start_line_ix]): 385 found = True 386 break 387 if not found: 388 print_error("Programmer error - Could not find the source line with" 389 + " a reference to function \"" + real_called_func_name 390 + "\".\n") 391 return 392 393 # Search forward through the source lines looking for a line whose 394 # indentation is the same or less than the start line. The end of our 395 # composite line should be the line preceding that line. 396 start_indent = get_line_indent(source_lines[start_line_ix]) 397 end_line_ix = line_ix 398 for end_line_ix in range(line_ix + 1, len(source_lines)): 399 if source_lines[end_line_ix].strip() == "": 400 continue 401 line_indent = get_line_indent(source_lines[end_line_ix]) 402 if line_indent <= start_indent: 403 end_line_ix -= 1 404 break 405 if start_line_ix != 0: 406 # Check to see whether the start line is a continuation of the prior 407 # line. 408 prior_line = source_lines[start_line_ix - 1] 409 prior_line_stripped = re.sub(r"[ ]*\\([\r\n]$)", " \\1", prior_line) 410 prior_line_indent = get_line_indent(prior_line) 411 if prior_line != prior_line_stripped and\ 412 prior_line_indent < start_indent: 413 start_line_ix -= 1 414 # Remove the backslash (continuation char) from prior line. 415 source_lines[start_line_ix] = prior_line_stripped 416 417 # Join the start line through the end line into a composite line. 418 composite_line = ''.join(map(str.strip, 419 source_lines[start_line_ix:end_line_ix + 1])) 420 # Insert one space after first "=" if there isn't one already. 421 composite_line = re.sub("=[ ]*([^ ])", "= \\1", composite_line, 1) 422 423 lvalue_regex = "[ ]*=[ ]+" + func_name_regex + ".*" 424 lvalue_string = re.sub(lvalue_regex, "", composite_line) 425 if lvalue_string == composite_line: 426 # i.e. the regex did not match so there are no lvalues. 427 lvalue_string = "" 428 lvalues_list = list(filter(None, map(str.strip, lvalue_string.split(",")))) 429 try: 430 lvalues = collections.OrderedDict() 431 except AttributeError: 432 # A non-ordered dict doesn't look as nice when printed but it will do. 433 lvalues = {} 434 ix = len(lvalues_list) * -1 435 for lvalue in lvalues_list: 436 lvalues[ix] = lvalue 437 ix += 1 438 lvalue_prefix_regex = "(.*=[ ]+)?" 439 called_func_name_regex = lvalue_prefix_regex + func_name_regex +\ 440 "[ ]*\\(.*" 441 called_func_name = re.sub(called_func_name_regex, "\\4", composite_line) 442 arg_list_etc = "(" + re.sub(pre_args_regex, "", composite_line) 443 if local_debug: 444 print_varx("aliases", aliases, indent=debug_indent) 445 print_varx("import_name_regex", import_name_regex, indent=debug_indent) 446 print_varx("func_name_regex", func_name_regex, indent=debug_indent) 447 print_varx("pre_args_regex", pre_args_regex, indent=debug_indent) 448 print_varx("start_line_ix", start_line_ix, indent=debug_indent) 449 print_varx("end_line_ix", end_line_ix, indent=debug_indent) 450 print_varx("composite_line", composite_line, indent=debug_indent) 451 print_varx("lvalue_regex", lvalue_regex, indent=debug_indent) 452 print_varx("lvalue_string", lvalue_string, indent=debug_indent) 453 print_varx("lvalues", lvalues, indent=debug_indent) 454 print_varx("called_func_name_regex", called_func_name_regex, 455 indent=debug_indent) 456 print_varx("called_func_name", called_func_name, indent=debug_indent) 457 print_varx("arg_list_etc", arg_list_etc, indent=debug_indent) 458 459 # Parse arg list... 460 # Initialize... 461 nest_level = -1 462 arg_ix = 0 463 args_list = [""] 464 for ix in range(0, len(arg_list_etc)): 465 char = arg_list_etc[ix] 466 # Set the nest_level based on whether we've encounted a parenthesis. 467 if char == "(": 468 nest_level += 1 469 if nest_level == 0: 470 continue 471 elif char == ")": 472 nest_level -= 1 473 if nest_level < 0: 474 break 475 476 # If we reach a comma at base nest level, we are done processing an 477 # argument so we increment arg_ix and initialize a new args_list entry. 478 if char == "," and nest_level == 0: 479 arg_ix += 1 480 args_list.append("") 481 continue 482 483 # For any other character, we append it it to the current arg list 484 # entry. 485 args_list[arg_ix] += char 486 487 # Trim whitespace from each list entry. 488 args_list = [arg.strip() for arg in args_list] 489 490 if arg_num < 0: 491 if abs(arg_num) > len(lvalues): 492 argument = lvalues 493 else: 494 argument = lvalues[arg_num] 495 elif arg_num == 0: 496 argument = called_func_name 497 else: 498 if arg_num > len(args_list): 499 argument = args_list 500 else: 501 argument = args_list[arg_num - 1] 502 503 if local_debug: 504 print_varx("args_list", args_list, indent=debug_indent) 505 print_varx("argument", argument, indent=debug_indent) 506 print_dashes(0, 120) 507 508 return argument 509 510 511def sprint_time(buffer=""): 512 r""" 513 Return the time in the following format. 514 515 Example: 516 517 The following python code... 518 519 sys.stdout.write(sprint_time()) 520 sys.stdout.write("Hi.\n") 521 522 Will result in the following type of output: 523 524 #(CDT) 2016/07/08 15:25:35 - Hi. 525 526 Example: 527 528 The following python code... 529 530 sys.stdout.write(sprint_time("Hi.\n")) 531 532 Will result in the following type of output: 533 534 #(CDT) 2016/08/03 17:12:05 - Hi. 535 536 The following environment variables will affect the formatting as 537 described: 538 NANOSECONDS This will cause the time stamps to be 539 precise to the microsecond (Yes, it 540 probably should have been named 541 MICROSECONDS but the convention was set 542 long ago so we're sticking with it). 543 Example of the output when environment 544 variable NANOSECONDS=1. 545 546 #(CDT) 2016/08/03 17:16:25.510469 - Hi. 547 548 SHOW_ELAPSED_TIME This will cause the elapsed time to be 549 included in the output. This is the 550 amount of time that has elapsed since the 551 last time this function was called. The 552 precision of the elapsed time field is 553 also affected by the value of the 554 NANOSECONDS environment variable. Example 555 of the output when environment variable 556 NANOSECONDS=0 and SHOW_ELAPSED_TIME=1. 557 558 #(CDT) 2016/08/03 17:17:40 - 0 - Hi. 559 560 Example of the output when environment variable NANOSECONDS=1 and 561 SHOW_ELAPSED_TIME=1. 562 563 #(CDT) 2016/08/03 17:18:47.317339 - 0.000046 - Hi. 564 565 Description of argument(s). 566 buffer This will be appended to the formatted 567 time string. 568 """ 569 570 global NANOSECONDS 571 global SHOW_ELAPSED_TIME 572 global sprint_time_last_seconds 573 global last_seconds_ix 574 575 seconds = time.time() 576 loc_time = time.localtime(seconds) 577 nanoseconds = "%0.6f" % seconds 578 pos = nanoseconds.find(".") 579 nanoseconds = nanoseconds[pos:] 580 581 time_string = time.strftime("#(%Z) %Y/%m/%d %H:%M:%S", loc_time) 582 if NANOSECONDS == "1": 583 time_string = time_string + nanoseconds 584 585 if SHOW_ELAPSED_TIME == "1": 586 cur_time_seconds = seconds 587 math_string = "%9.9f" % cur_time_seconds + " - " + "%9.9f" % \ 588 sprint_time_last_seconds[last_seconds_ix] 589 elapsed_seconds = eval(math_string) 590 if NANOSECONDS == "1": 591 elapsed_seconds = "%11.6f" % elapsed_seconds 592 else: 593 elapsed_seconds = "%4i" % elapsed_seconds 594 sprint_time_last_seconds[last_seconds_ix] = cur_time_seconds 595 time_string = time_string + " - " + elapsed_seconds 596 597 return time_string + " - " + buffer 598 599 600def sprint_timen(buffer=""): 601 r""" 602 Append a line feed to the buffer, pass it to sprint_time and return the 603 result. 604 """ 605 606 return sprint_time(buffer + "\n") 607 608 609def sprint_error(buffer=""): 610 r""" 611 Return a standardized error string. This includes: 612 - A time stamp 613 - The "**ERROR**" string 614 - The caller's buffer string. 615 616 Example: 617 618 The following python code... 619 620 print(sprint_error("Oops.\n")) 621 622 Will result in the following type of output: 623 624 #(CDT) 2016/08/03 17:12:05 - **ERROR** Oops. 625 626 Description of argument(s). 627 buffer This will be appended to the formatted 628 error string. 629 """ 630 631 return sprint_time() + "**ERROR** " + buffer 632 633 634# Implement "constants" with functions. 635def digit_length_in_bits(): 636 r""" 637 Return the digit length in bits. 638 """ 639 640 return 4 641 642 643def word_length_in_digits(): 644 r""" 645 Return the word length in digits. 646 """ 647 648 return 8 649 650 651def bit_length(number): 652 r""" 653 Return the bit length of the number. 654 655 Description of argument(s): 656 number The number to be analyzed. 657 """ 658 659 if number < 0: 660 # Convert negative numbers to positive and subtract one. The 661 # following example illustrates the reason for this: 662 # Consider a single nibble whose signed values can range from -8 to 7 663 # (0x8 to 0x7). A value of 0x7 equals 0b0111. Therefore, its length 664 # in bits is 3. Since the negative bit (i.e. 0b1000) is not set, the 665 # value 7 clearly will fit in one nibble. With -8 = 0x8 = 0b1000, one 666 # has the smallest negative value that will fit. Note that it 667 # requires 3 bits of 0. So by converting a number value of -8 to a 668 # working_number of 7, this function can accurately calculate the 669 # number of bits and therefore nibbles required to represent the 670 # number in print. 671 working_number = abs(number) - 1 672 else: 673 working_number = number 674 675 # Handle the special case of the number 0. 676 if working_number == 0: 677 return 0 678 679 return len(bin(working_number)) - 2 680 681 682def get_req_num_hex_digits(number): 683 r""" 684 Return the required number of hex digits required to display the given 685 number. 686 687 The returned value will always be rounded up to the nearest multiple of 8. 688 689 Description of argument(s): 690 number The number to be analyzed. 691 """ 692 693 if number < 0: 694 # Convert negative numbers to positive and subtract one. The 695 # following example illustrates the reason for this: 696 # Consider a single nibble whose signed values can range from -8 to 7 697 # (0x8 to 0x7). A value of 0x7 equals 0b0111. Therefore, its length 698 # in bits is 3. Since the negative bit (i.e. 0b1000) is not set, the 699 # value 7 clearly will fit in one nibble. With -8 = 0x8 = 0b1000, one 700 # has the smallest negative value that will fit. Note that it 701 # requires 3 bits of 0. So by converting a number value of -8 to a 702 # working_number of 7, this function can accurately calculate the 703 # number of bits and therefore nibbles required to represent the 704 # number in print. 705 working_number = abs(number) - 1 706 else: 707 working_number = number 708 709 # Handle the special case of the number 0. 710 if working_number == 0: 711 return word_length_in_digits() 712 713 num_length_in_bits = bit_length(working_number) 714 num_hex_digits, remainder = divmod(num_length_in_bits, 715 digit_length_in_bits()) 716 if remainder > 0: 717 # Example: the number 7 requires 3 bits. The divmod above produces, 718 # 0 with remainder of 3. So because we have a remainder, we increment 719 # num_hex_digits from 0 to 1. 720 num_hex_digits += 1 721 722 # Check to see whether the negative bit is set. This is the left-most 723 # bit in the highest order digit. 724 negative_mask = 2 ** (num_hex_digits * 4 - 1) 725 if working_number & negative_mask: 726 # If a number that is intended to be positive has its negative bit 727 # on, an additional digit will be required to represent it correctly 728 # in print. 729 num_hex_digits += 1 730 731 num_words, remainder = divmod(num_hex_digits, word_length_in_digits()) 732 if remainder > 0 or num_words == 0: 733 num_words += 1 734 735 # Round up to the next word length in digits. 736 return num_words * word_length_in_digits() 737 738 739def dft_num_hex_digits(): 740 r""" 741 Return the default number of hex digits to be used to represent a hex 742 number in print. 743 744 The value returned is a function of sys.maxsize. 745 """ 746 747 global _gen_print_dft_num_hex_digits_ 748 try: 749 return _gen_print_dft_num_hex_digits_ 750 except NameError: 751 _gen_print_dft_num_hex_digits_ = get_req_num_hex_digits(sys.maxsize) 752 return _gen_print_dft_num_hex_digits_ 753 754 755# Create constant functions to describe various types of dictionaries. 756def dict_type(): 757 return 1 758 759 760def ordered_dict_type(): 761 return 2 762 763 764def dot_dict_type(): 765 return 3 766 767 768def normalized_dict_type(): 769 return 4 770 771 772def proxy_dict_type(): 773 return 5 774 775 776def is_dict(var_value): 777 r""" 778 Return non-zero if var_value is a type of dictionary and 0 if it is not. 779 780 The specific non-zero value returned will indicate what type of dictionary 781 var_value is (see constant functions above). 782 783 Description of argument(s): 784 var_value The object to be analyzed to determine 785 whether it is a dictionary and if so, what 786 type of dictionary. 787 """ 788 789 if isinstance(var_value, dict): 790 return dict_type() 791 try: 792 if isinstance(var_value, collections.OrderedDict): 793 return ordered_dict_type() 794 except AttributeError: 795 pass 796 try: 797 if isinstance(var_value, DotDict): 798 return dot_dict_type() 799 except NameError: 800 pass 801 try: 802 if isinstance(var_value, NormalizedDict): 803 return normalized_dict_type() 804 except NameError: 805 pass 806 try: 807 if str(type(var_value)).split("'")[1] == "dictproxy": 808 return proxy_dict_type() 809 except NameError: 810 pass 811 return 0 812 813 814def get_int_types(): 815 r""" 816 Return a tuple consisting of the valid integer data types for the system 817 and version of python being run. 818 819 Example: 820 (int, long) 821 """ 822 823 try: 824 int_types = (int, long) 825 except NameError: 826 int_types = (int,) 827 return int_types 828 829 830def get_string_types(): 831 r""" 832 Return a tuple consisting of the valid string data types for the system 833 and version of python being run. 834 835 Example: 836 (str, unicode) 837 """ 838 839 try: 840 string_types = (str, unicode) 841 except NameError: 842 string_types = (bytes, str) 843 return string_types 844 845 846def valid_fmts(): 847 r""" 848 Return a list of the valid formats that can be specified for the fmt 849 argument of the sprint_varx function (defined below). 850 """ 851 852 return [ 853 'hexa', 854 'octal', 855 'binary', 856 'blank', 857 'terse', 858 'quote_keys', 859 'show_type'] 860 861 862def create_fmt_definition(): 863 r""" 864 Create a string consisting of function-definition code that can be 865 executed to create constant fmt definition functions. 866 867 These functions can be used by callers of sprint_var/sprint_varx to set 868 the fmt argument correctly. 869 870 Likewise, the sprint_varx function will use these generated functions to 871 correctly interpret the fmt argument. 872 873 Example output from this function: 874 875 def hexa(): 876 return 0x00000001 877 def octal_fmt(): 878 return 0x00000002 879 etc. 880 """ 881 882 buffer = "" 883 bits = 0x00000001 884 for fmt_name in valid_fmts(): 885 buffer += "def " + fmt_name + "():\n" 886 buffer += " return " + "0x%08x" % bits + "\n" 887 bits = bits << 1 888 return buffer 889 890 891# Dynamically create fmt definitions (for use with the fmt argument of 892# sprint_varx function): 893exec(create_fmt_definition()) 894 895 896def list_pop(a_list, index=0, default=None): 897 r""" 898 Pop the list entry indicated by the index and return the entry. If no 899 such entry exists, return default. 900 901 Note that the list passed to this function will be modified. 902 903 Description of argument(s): 904 a_list The list from which an entry is to be 905 popped. 906 index The index indicating which entry is to be 907 popped. 908 default The value to be returned if there is no 909 entry at the given index location. 910 """ 911 try: 912 return a_list.pop(index) 913 except IndexError: 914 return default 915 916 917def parse_fmt(fmt): 918 r""" 919 Parse the fmt argument and return a tuple consisting of a format and a 920 child format. 921 922 This function was written for use by the sprint_varx function defined in 923 this module. 924 925 When sprint_varx is processing a multi-level object such as a list or 926 dictionary (which in turn may contain other lists or dictionaries), it 927 will use the fmt value to dictate the print formatting of the current 928 level and the child_fmt value to dictate the print formatting of 929 subordinate levels. Consider the following example: 930 931 python code example: 932 933 ord_dict = \ 934 collections.OrderedDict([ 935 ('one', 1), 936 ('two', 2), 937 ('sub', 938 collections.OrderedDict([ 939 ('three', 3), ('four', 4)]))]) 940 941 print_var(ord_dict) 942 943 This would generate the following output: 944 945 ord_dict: 946 ord_dict[one]: 1 947 ord_dict[two]: 2 948 ord_dict[sub]: 949 ord_dict[sub][three]: 3 950 ord_dict[sub][four]: 4 951 952 The first level in this example is the line that simply says "ord_dict". 953 The second level is comprised of the dictionary entries with the keys 954 'one', 'two' and 'sub'. The third level is comprised of the last 2 lines 955 (i.e. printed values 3 and 4). 956 957 Given the data structure shown above, the programmer could code the 958 following where fmt is a simple integer value set by calling the terse() 959 function. 960 961 print_var(ord_dict, fmt=terse()) 962 963 The output would look like this: 964 965 ord_dict: 966 [one]: 1 967 [two]: 2 968 [sub]: 969 [three]: 3 970 [four]: 4 971 972 Note the terse format where the name of the object ("ord_dict") is not 973 repeated on every line as it was in example #1. 974 975 If the programmer wishes to get more granular with the fmt argument, 976 he/she can specify it as a list where each entry corresponds to a level of 977 the object being printed. The last such list entry governs the print 978 formatting of all subordinate parts of the given object. 979 980 Look at each of the following code examples and their corresponding 981 output. See how the show_type() formatting affects the printing depending 982 on which position it occupies in the fmt list argument: 983 984 print_var(ord_dict, fmt=[show_type()]) 985 986 ord_dict: <collections.OrderedDict> 987 ord_dict[one]: 1 <int> 988 ord_dict[two]: 2 <int> 989 ord_dict[sub]: <collections.OrderedDict> 990 ord_dict[sub][three]: 3 <int> 991 ord_dict[sub][four]: 4 <int> 992 993 print_var(ord_dict, fmt=[0, show_type()]) 994 995 ord_dict: 996 ord_dict[one]: 1 <int> 997 ord_dict[two]: 2 <int> 998 ord_dict[sub]: <collections.OrderedDict> 999 ord_dict[sub][three]: 3 <int> 1000 ord_dict[sub][four]: 4 <int> 1001 1002 print_var(ord_dict, fmt=[0, 0, show_type()]) 1003 1004 ord_dict: 1005 ord_dict[one]: 1 1006 ord_dict[two]: 2 1007 ord_dict[sub]: 1008 ord_dict[sub][three]: 3 <int> 1009 ord_dict[sub][four]: 4 <int> 1010 1011 Description of argument(s): 1012 fmt The format argument such as is passed to 1013 sprint_varx. This argument may be an 1014 integer or a list of integers. See the 1015 prolog of sprint_varx for more details. 1016 """ 1017 1018 # Make a deep copy of the fmt argument in order to avoid modifying the 1019 # caller's fmt value when it is a list. 1020 fmt = copy.deepcopy(fmt) 1021 try: 1022 # Assume fmt is a list. Pop the first element from the list. 1023 first_element = list_pop(fmt, index=0, default=0) 1024 # Return the first list element along with either 1) the remainder of 1025 # the fmt list if not null or 2) another copy of the first element. 1026 return first_element, fmt if len(fmt) else first_element 1027 except AttributeError: 1028 # fmt is not a list so treat it as a simple integer value. 1029 return fmt, fmt 1030 1031 1032def sprint_varx(var_name, 1033 var_value, 1034 fmt=0, 1035 indent=dft_indent, 1036 col1_width=dft_col1_width, 1037 trailing_char="\n", 1038 key_list=None, 1039 delim=":"): 1040 r""" 1041 Print the var name/value passed to it. If the caller lets col1_width 1042 default, the printing lines up nicely with output generated by the 1043 print_time functions. 1044 1045 Note that the sprint_var function (defined below) can be used to call this 1046 function so that the programmer does not need to pass the var_name. 1047 sprint_var will figure out the var_name. The sprint_var function is the 1048 one that would normally be used by the general user. 1049 1050 For example, the following python code: 1051 1052 first_name = "Mike" 1053 print_time("Doing this...\n") 1054 print_varx("first_name", first_name) 1055 print_time("Doing that...\n") 1056 1057 Will generate output like this: 1058 1059 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this... 1060 first_name: Mike 1061 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that... 1062 1063 This function recognizes several complex types of data such as dict, list 1064 or tuple. 1065 1066 For example, the following python code: 1067 1068 my_dict = dict(one=1, two=2, three=3) 1069 print_var(my_dict) 1070 1071 Will generate the following output: 1072 1073 my_dict: 1074 my_dict[three]: 3 1075 my_dict[two]: 2 1076 my_dict[one]: 1 1077 1078 Description of argument(s). 1079 var_name The name of the variable to be printed. 1080 var_value The value of the variable to be printed. 1081 fmt A bit map to dictate the format of the 1082 output. For printing multi-level objects 1083 like lists and dictionaries, this argument 1084 may also be a list of bit maps. The first 1085 list element pertains to the highest level 1086 of output, the second element pertains to 1087 the 2nd level of output, etc. The last 1088 element in the list pertains to all 1089 subordinate levels. The bits can be set 1090 using the dynamically created functionhs 1091 above. Example: sprint_varx("var1", var1, 1092 fmt=terse()). Note that these values can 1093 be OR'ed together: print_var(var1, hexa() 1094 | terse()). If the caller ORs mutually 1095 exclusive bits (hexa() | octal()), 1096 behavior is not guaranteed. The following 1097 features are supported: 1098 hexa Print all integer values in hexadecimal 1099 format. 1100 octal Print all integer values in octal format. 1101 binary Print all integer values in binary format. 1102 blank For blank string values, print "<blank>" 1103 instead of an actual blank. 1104 terse For structured values like dictionaries, 1105 lists, etc. do not repeat the name of the 1106 variable on each line to the right of the 1107 key or subscript value. Example: print 1108 "[key1]" instead of "my_dict[key1]". 1109 quote_keys Quote dictionary keys in the output. 1110 Example: my_dict['key1'] instead of 1111 my_dict[key1]. 1112 show_type Show the type of the data in angled 1113 brackets just to the right of the data. 1114 indent The number of spaces to indent the output. 1115 col1_width The width of the output column containing 1116 the variable name. The default value of 1117 this is adjusted so that the var_value 1118 lines up with text printed via the 1119 print_time function. 1120 trailing_char The character to be used at the end of the 1121 returned string. The default value is a 1122 line feed. 1123 key_list A list of which dictionary keys should be 1124 printed. All others keys will be skipped. 1125 Each value in key_list will be regarded 1126 as a regular expression and it will be 1127 regarded as anchored to the beginning and 1128 ends of the dictionary key being 1129 referenced. For example if key_list is 1130 ["one", "two"], the resulting regex used 1131 will be "^one|two$", i.e. only keys "one" 1132 and "two" from the var_value dictionary 1133 will be printed. As another example, if 1134 the caller were to specify a key_list of 1135 ["one.*"], then only dictionary keys whose 1136 names begin with "one" will be printed. 1137 Note: This argument pertains only to 1138 var_values which are dictionaries. 1139 delim The value to be used to delimit the 1140 variable name from the variable value in 1141 the output. 1142 """ 1143 1144 fmt, child_fmt = parse_fmt(fmt) 1145 1146 if fmt & show_type(): 1147 type_str = "<" + str(type(var_value)).split("'")[1] + ">" 1148 # Compose object type categories. 1149 int_types = get_int_types() 1150 string_types = get_string_types() 1151 simple_types = int_types + string_types + (float, bool, type, type(None)) 1152 # Determine the type. 1153 if type(var_value) in simple_types: 1154 # The data type is simple in the sense that it has no subordinate 1155 # parts. 1156 # Adjust col1_width. 1157 col1_width = col1_width - indent 1158 # Set default value for value_format. 1159 value_format = "%s" 1160 # Process format requests. 1161 if type(var_value) in int_types: 1162 # Process format values pertaining to int types. 1163 if fmt & hexa(): 1164 num_hex_digits = max(dft_num_hex_digits(), 1165 get_req_num_hex_digits(var_value)) 1166 # Convert a negative number to its positive twos complement 1167 # for proper printing. For example, instead of printing -1 as 1168 # "0x-000000000000001" it will be printed as 1169 # "0xffffffffffffffff". 1170 var_value = var_value & (2 ** (num_hex_digits * 4) - 1) 1171 value_format = "0x%0" + str(num_hex_digits) + "x" 1172 elif fmt & octal(): 1173 value_format = "0o%016o" 1174 elif fmt & binary(): 1175 num_digits, remainder = \ 1176 divmod(max(bit_length(var_value), 1), 8) 1177 num_digits *= 8 1178 if remainder: 1179 num_digits += 8 1180 num_digits += 2 1181 value_format = '#0' + str(num_digits) + 'b' 1182 var_value = format(var_value, value_format) 1183 value_format = "%s" 1184 elif type(var_value) in string_types: 1185 # Process format values pertaining to string types. 1186 if fmt & blank() and var_value == "": 1187 value_format = "%s" 1188 var_value = "<blank>" 1189 elif type(var_value) is type: 1190 var_value = str(var_value).split("'")[1] 1191 format_string = "%" + str(indent) + "s%-" + str(col1_width) + "s" \ 1192 + value_format 1193 if fmt & show_type(): 1194 if var_value != "": 1195 format_string += " " 1196 format_string += type_str 1197 format_string += trailing_char 1198 if fmt & terse(): 1199 # Strip everything leading up to the first left square brace. 1200 var_name = re.sub(r".*\[", "[", var_name) 1201 if value_format == "0x%08x": 1202 return format_string % ("", str(var_name) + delim, 1203 var_value & 0xffffffff) 1204 else: 1205 return format_string % ("", str(var_name) + delim, var_value) 1206 else: 1207 # The data type is complex in the sense that it has subordinate parts. 1208 if fmt & terse(): 1209 # Strip everything leading up to the first square brace. 1210 loc_var_name = re.sub(r".*\[", "[", var_name) 1211 else: 1212 loc_var_name = var_name 1213 format_string = "%" + str(indent) + "s%s\n" 1214 buffer = format_string % ("", loc_var_name + ":") 1215 if fmt & show_type(): 1216 buffer = buffer.replace("\n", " " + type_str + "\n") 1217 indent += 2 1218 try: 1219 length = len(var_value) 1220 except TypeError: 1221 length = 0 1222 ix = 0 1223 loc_trailing_char = "\n" 1224 if is_dict(var_value): 1225 if type(child_fmt) is list: 1226 child_quote_keys = (child_fmt[0] & quote_keys()) 1227 else: 1228 child_quote_keys = (child_fmt & quote_keys()) 1229 for key, value in var_value.items(): 1230 if key_list is not None: 1231 key_list_regex = "^" + "|".join(key_list) + "$" 1232 if not re.match(key_list_regex, key): 1233 continue 1234 ix += 1 1235 if ix == length: 1236 loc_trailing_char = trailing_char 1237 if child_quote_keys: 1238 key = "'" + key + "'" 1239 key = "[" + str(key) + "]" 1240 buffer += sprint_varx(var_name + key, value, child_fmt, indent, 1241 col1_width, loc_trailing_char, key_list) 1242 elif type(var_value) in (list, tuple, set): 1243 for key, value in enumerate(var_value): 1244 ix += 1 1245 if ix == length: 1246 loc_trailing_char = trailing_char 1247 key = "[" + str(key) + "]" 1248 buffer += sprint_varx(var_name + key, value, child_fmt, indent, 1249 col1_width, loc_trailing_char, key_list) 1250 elif isinstance(var_value, argparse.Namespace): 1251 for key in var_value.__dict__: 1252 ix += 1 1253 if ix == length: 1254 loc_trailing_char = trailing_char 1255 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \ 1256 + ", var_value." + key + ", child_fmt, indent," \ 1257 + " col1_width, loc_trailing_char, key_list)" 1258 exec(cmd_buf) 1259 else: 1260 var_type = type(var_value).__name__ 1261 func_name = sys._getframe().f_code.co_name 1262 var_value = "<" + var_type + " type not supported by " + \ 1263 func_name + "()>" 1264 value_format = "%s" 1265 indent -= 2 1266 # Adjust col1_width. 1267 col1_width = col1_width - indent 1268 format_string = "%" + str(indent) + "s%-" \ 1269 + str(col1_width) + "s" + value_format + trailing_char 1270 return format_string % ("", str(var_name) + ":", var_value) 1271 1272 return buffer 1273 1274 return "" 1275 1276 1277def sprint_var(*args, **kwargs): 1278 r""" 1279 Figure out the name of the first argument for the caller and then call 1280 sprint_varx with it. Therefore, the following 2 calls are equivalent: 1281 sprint_varx("var1", var1) 1282 sprint_var(var1) 1283 1284 See sprint_varx for description of arguments. 1285 """ 1286 1287 stack_frame = 2 1288 caller_func_name = sprint_func_name(2) 1289 if caller_func_name.endswith("print_var"): 1290 stack_frame += 1 1291 # Get the name of the first variable passed to this function. 1292 var_name = get_arg_name(None, 1, stack_frame) 1293 return sprint_varx(var_name, *args, **kwargs) 1294 1295 1296def sprint_vars(*args, **kwargs): 1297 r""" 1298 Sprint the values of one or more variables. 1299 1300 Description of argument(s): 1301 args The variable values which are to be 1302 printed. 1303 kwargs See sprint_varx (above) for description of 1304 additional arguments. 1305 """ 1306 1307 stack_frame = 2 1308 caller_func_name = sprint_func_name(2) 1309 if caller_func_name.endswith("print_vars"): 1310 stack_frame += 1 1311 1312 buffer = "" 1313 arg_num = 1 1314 for var_value in args: 1315 var_name = get_arg_name(None, arg_num, stack_frame) 1316 buffer += sprint_varx(var_name, var_value, **kwargs) 1317 arg_num += 1 1318 1319 return buffer 1320 1321 1322def sprint_dashes(indent=dft_indent, 1323 width=80, 1324 line_feed=1, 1325 char="-"): 1326 r""" 1327 Return a string of dashes to the caller. 1328 1329 Description of argument(s): 1330 indent The number of characters to indent the 1331 output. 1332 width The width of the string of dashes. 1333 line_feed Indicates whether the output should end 1334 with a line feed. 1335 char The character to be repeated in the output 1336 string. 1337 """ 1338 1339 width = int(width) 1340 buffer = " " * int(indent) + char * width 1341 if line_feed: 1342 buffer += "\n" 1343 1344 return buffer 1345 1346 1347def sindent(text="", 1348 indent=0): 1349 r""" 1350 Pre-pend the specified number of characters to the text string (i.e. 1351 indent it) and return it. 1352 1353 Description of argument(s): 1354 text The string to be indented. 1355 indent The number of characters to indent the 1356 string. 1357 """ 1358 1359 format_string = "%" + str(indent) + "s%s" 1360 buffer = format_string % ("", text) 1361 1362 return buffer 1363 1364 1365func_line_style_std = None 1366func_line_style_short = 1 1367 1368 1369def sprint_func_line(stack_frame, style=None): 1370 r""" 1371 For the given stack_frame, return a formatted string containing the 1372 function name and all its arguments. 1373 1374 Example: 1375 1376 func1(last_name = 'walsh', first_name = 'mikey') 1377 1378 Description of argument(s): 1379 stack_frame A stack frame (such as is returned by 1380 inspect.stack()). 1381 style Indicates the style or formatting of the 1382 result string. Acceptable values are 1383 shown above. 1384 1385 Description of styles: 1386 func_line_style_std The standard formatting. 1387 func_line_style_short 1) The self parm (associated with methods) 1388 will be dropped. 2) The args and kwargs 1389 values will be treated as special. In 1390 both cases the arg name ('args' or 1391 'kwargs') will be dropped and only the 1392 values will be shown. 1393 """ 1394 1395 func_name = str(stack_frame[3]) 1396 if func_name == "?": 1397 # "?" is the name used when code is not in a function. 1398 func_name = "(none)" 1399 1400 if func_name == "<module>": 1401 # If the func_name is the "main" program, we simply get the command 1402 # line call string. 1403 func_and_args = ' '.join(sys.argv) 1404 else: 1405 # Get the program arguments. 1406 (args, varargs, keywords, locals) =\ 1407 inspect.getargvalues(stack_frame[0]) 1408 1409 args_list = [] 1410 for arg_name in filter(None, args + [varargs, keywords]): 1411 # Get the arg value from frame locals. 1412 arg_value = locals[arg_name] 1413 if arg_name == 'self': 1414 if style == func_line_style_short: 1415 continue 1416 # Manipulations to improve output for class methods. 1417 func_name = arg_value.__class__.__name__ + "." + func_name 1418 args_list.append(arg_name + " = <self>") 1419 elif (style == func_line_style_short 1420 and arg_name == 'args' 1421 and type(arg_value) in (list, tuple)): 1422 if len(arg_value) == 0: 1423 continue 1424 args_list.append(repr(', '.join(arg_value))) 1425 elif (style == func_line_style_short 1426 and arg_name == 'kwargs' 1427 and type(arg_value) is dict): 1428 for key, value in arg_value.items(): 1429 args_list.append(key + "=" + repr(value)) 1430 else: 1431 args_list.append(arg_name + " = " + repr(arg_value)) 1432 args_str = "(" + ', '.join(map(str, args_list)) + ")" 1433 1434 # Now we need to print this in a nicely-wrapped way. 1435 func_and_args = func_name + args_str 1436 1437 return func_and_args 1438 1439 1440def sprint_call_stack(indent=0, 1441 stack_frame_ix=0, 1442 style=None): 1443 r""" 1444 Return a call stack report for the given point in the program with line 1445 numbers, function names and function parameters and arguments. 1446 1447 Sample output: 1448 1449 ------------------------------------------------------------------------- 1450 Python function call stack 1451 1452 Line # Function name and arguments 1453 ------ ------------------------------------------------------------------ 1454 424 sprint_call_stack() 1455 4 print_call_stack() 1456 31 func1(last_name = 'walsh', first_name = 'mikey') 1457 59 /tmp/scr5.py 1458 ------------------------------------------------------------------------- 1459 1460 Description of argument(s): 1461 indent The number of characters to indent each 1462 line of output. 1463 stack_frame_ix The index of the first stack frame which 1464 is to be returned. 1465 style See the sprint_line_func prolog above for 1466 details. 1467 """ 1468 1469 buffer = "" 1470 buffer += sprint_dashes(indent) 1471 buffer += sindent("Python function call stack\n\n", indent) 1472 buffer += sindent("Line # Function name and arguments\n", indent) 1473 buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73) 1474 1475 # Grab the current program stack. 1476 work_around_inspect_stack_cwd_failure() 1477 current_stack = inspect.stack() 1478 1479 # Process each frame in turn. 1480 format_string = "%6s %s\n" 1481 ix = 0 1482 for stack_frame in current_stack: 1483 if ix < stack_frame_ix: 1484 ix += 1 1485 continue 1486 # Make the line number shown to be the line where one finds the line 1487 # shown. 1488 try: 1489 line_num = str(current_stack[ix + 1][2]) 1490 except IndexError: 1491 line_num = "" 1492 func_and_args = sprint_func_line(stack_frame, style=style) 1493 1494 buffer += sindent(format_string % (line_num, func_and_args), indent) 1495 ix += 1 1496 1497 buffer += sprint_dashes(indent) 1498 1499 return buffer 1500 1501 1502def sprint_executing(stack_frame_ix=None, style=None): 1503 r""" 1504 Print a line indicating what function is executing and with what parameter 1505 values. This is useful for debugging. 1506 1507 Sample output: 1508 1509 #(CDT) 2016/08/25 17:54:27 - Executing: func1(x = 1) 1510 1511 Description of argument(s): 1512 stack_frame_ix The index of the stack frame whose 1513 function info should be returned. If the 1514 caller does not specify a value, this 1515 function will set the value to 1 which is 1516 the index of the caller's stack frame. If 1517 the caller is the wrapper function 1518 "print_executing", this function will bump 1519 it up by 1. 1520 style See the sprint_line_func prolog above for 1521 details. 1522 """ 1523 1524 # If user wants default stack_frame_ix. 1525 if stack_frame_ix is None: 1526 func_name = sys._getframe().f_code.co_name 1527 caller_func_name = sys._getframe(1).f_code.co_name 1528 if caller_func_name.endswith(func_name[1:]): 1529 stack_frame_ix = 2 1530 else: 1531 stack_frame_ix = 1 1532 1533 work_around_inspect_stack_cwd_failure() 1534 stack_frame = inspect.stack()[stack_frame_ix] 1535 1536 func_and_args = sprint_func_line(stack_frame, style) 1537 1538 return sprint_time() + "Executing: " + func_and_args + "\n" 1539 1540 1541def sprint_pgm_header(indent=0, 1542 linefeed=1): 1543 r""" 1544 Return a standardized header that programs should print at the beginning 1545 of the run. It includes useful information like command line, pid, 1546 userid, program parameters, etc. 1547 1548 Description of argument(s): 1549 indent The number of characters to indent each 1550 line of output. 1551 linefeed Indicates whether a line feed be included 1552 at the beginning and end of the report. 1553 """ 1554 1555 col1_width = dft_col1_width + indent 1556 1557 buffer = "" 1558 if linefeed: 1559 buffer = "\n" 1560 1561 if robot_env: 1562 suite_name = BuiltIn().get_variable_value("${suite_name}") 1563 buffer += sindent(sprint_time("Running test suite \"" + suite_name 1564 + "\".\n"), indent) 1565 1566 buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent) 1567 buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n", 1568 indent) 1569 buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent, 1570 col1_width) 1571 # We want the output to show a customized name for the pid and pgid but 1572 # we want it to look like a valid variable name. Therefore, we'll use 1573 # pgm_name_var_name which was set when this module was imported. 1574 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent, 1575 col1_width) 1576 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent, 1577 col1_width) 1578 userid_num = str(os.geteuid()) 1579 try: 1580 username = os.getlogin() 1581 except OSError: 1582 if userid_num == "0": 1583 username = "root" 1584 else: 1585 username = "?" 1586 buffer += sprint_varx("uid", userid_num + " (" + username 1587 + ")", 0, indent, col1_width) 1588 buffer += sprint_varx("gid", str(os.getgid()) + " (" 1589 + str(grp.getgrgid(os.getgid()).gr_name) + ")", 0, 1590 indent, col1_width) 1591 buffer += sprint_varx("host_name", socket.gethostname(), 0, indent, 1592 col1_width) 1593 try: 1594 DISPLAY = os.environ['DISPLAY'] 1595 except KeyError: 1596 DISPLAY = "" 1597 buffer += sprint_var(DISPLAY, 0, indent, col1_width) 1598 PYTHON_VERSION = os.environ.get('PYTHON_VERSION', None) 1599 if PYTHON_VERSION is not None: 1600 buffer += sprint_var(PYTHON_VERSION) 1601 PYTHON_PGM_PATH = os.environ.get('PYTHON_PGM_PATH', None) 1602 if PYTHON_PGM_PATH is not None: 1603 buffer += sprint_var(PYTHON_PGM_PATH) 1604 python_version = sys.version.replace("\n", "") 1605 buffer += sprint_var(python_version) 1606 ROBOT_VERSION = os.environ.get('ROBOT_VERSION', None) 1607 if ROBOT_VERSION is not None: 1608 buffer += sprint_var(ROBOT_VERSION) 1609 ROBOT_PGM_PATH = os.environ.get('ROBOT_PGM_PATH', None) 1610 if ROBOT_PGM_PATH is not None: 1611 buffer += sprint_var(ROBOT_PGM_PATH) 1612 1613 # TODO: Add code to print caller's parms. 1614 1615 # __builtin__.arg_obj is created by the get_arg module function, 1616 # gen_get_options. 1617 try: 1618 buffer += ga.sprint_args(__builtin__.arg_obj, indent) 1619 except AttributeError: 1620 pass 1621 1622 if robot_env: 1623 # Get value of global parm_list. 1624 parm_list = BuiltIn().get_variable_value("${parm_list}") 1625 1626 for parm in parm_list: 1627 parm_value = BuiltIn().get_variable_value("${" + parm + "}") 1628 buffer += sprint_varx(parm, parm_value, 0, indent, col1_width) 1629 1630 # Setting global program_pid. 1631 BuiltIn().set_global_variable("${program_pid}", os.getpid()) 1632 1633 if linefeed: 1634 buffer += "\n" 1635 1636 return buffer 1637 1638 1639def sprint_error_report(error_text="\n", 1640 indent=2, 1641 format=None): 1642 r""" 1643 Return a string with a standardized report which includes the caller's 1644 error text, the call stack and the program header. 1645 1646 Description of argument(s): 1647 error_text The error text to be included in the 1648 report. The caller should include any 1649 needed linefeeds. 1650 indent The number of characters to indent each 1651 line of output. 1652 format Long or short format. Long includes 1653 extras like lines of dashes, call stack, 1654 etc. 1655 """ 1656 1657 # Process input. 1658 indent = int(indent) 1659 if format is None: 1660 if robot_env: 1661 format = 'short' 1662 else: 1663 format = 'long' 1664 error_text = error_text.rstrip('\n') + '\n' 1665 1666 if format == 'short': 1667 return sprint_error(error_text) 1668 1669 buffer = "" 1670 buffer += sprint_dashes(width=120, char="=") 1671 buffer += sprint_error(error_text) 1672 buffer += "\n" 1673 # Calling sprint_call_stack with stack_frame_ix of 0 causes it to show 1674 # itself and this function in the call stack. This is not helpful to a 1675 # debugger and is therefore clutter. We will adjust the stack_frame_ix to 1676 # hide that information. 1677 stack_frame_ix = 1 1678 caller_func_name = sprint_func_name(2) 1679 if caller_func_name.endswith("print_error_report"): 1680 stack_frame_ix += 1 1681 buffer += sprint_call_stack(indent, stack_frame_ix) 1682 buffer += sprint_pgm_header(indent) 1683 buffer += sprint_dashes(width=120, char="=") 1684 1685 return buffer 1686 1687 1688def sprint_issuing(cmd_buf, 1689 test_mode=0): 1690 r""" 1691 Return a line indicating a command that the program is about to execute. 1692 1693 Sample output for a cmd_buf of "ls" 1694 1695 #(CDT) 2016/08/25 17:57:36 - Issuing: ls 1696 1697 Description of argument(s): 1698 cmd_buf The command to be executed by caller. 1699 test_mode With test_mode set, the output will look 1700 like this: 1701 1702 #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls 1703 1704 """ 1705 1706 buffer = sprint_time() 1707 if test_mode: 1708 buffer += "(test_mode) " 1709 if type(cmd_buf) is list: 1710 # Assume this is a robot command in the form of a list. 1711 cmd_buf = ' '.join([str(element) for element in cmd_buf]) 1712 buffer += "Issuing: " + cmd_buf + "\n" 1713 1714 return buffer 1715 1716 1717def sprint_pgm_footer(): 1718 r""" 1719 Return a standardized footer that programs should print at the end of the 1720 program run. It includes useful information like total run time, etc. 1721 """ 1722 1723 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n" 1724 1725 total_time = time.time() - start_time 1726 total_time_string = "%0.6f" % total_time 1727 1728 buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string) 1729 buffer += "\n" 1730 1731 return buffer 1732 1733 1734def sprint(buffer=""): 1735 r""" 1736 Simply return the user's buffer. This function is used by the qprint and 1737 dprint functions defined dynamically below, i.e. it would not normally be 1738 called for general use. 1739 1740 Description of argument(s). 1741 buffer This will be returned to the caller. 1742 """ 1743 1744 try: 1745 return str(buffer) 1746 except UnicodeEncodeError: 1747 return buffer 1748 1749 1750def sprintn(buffer=""): 1751 r""" 1752 Simply return the user's buffer with a line feed. This function is used 1753 by the qprint and dprint functions defined dynamically below, i.e. it 1754 would not normally be called for general use. 1755 1756 Description of argument(s). 1757 buffer This will be returned to the caller. 1758 """ 1759 1760 try: 1761 buffer = str(buffer) + "\n" 1762 except UnicodeEncodeError: 1763 buffer = buffer + "\n" 1764 1765 return buffer 1766 1767 1768def gp_print(buffer, 1769 stream='stdout'): 1770 r""" 1771 Print the buffer using either sys.stdout.write or BuiltIn().log_to_console 1772 depending on whether we are running in a robot environment. 1773 1774 This function is intended for use only by other functions in this module. 1775 1776 Description of argument(s): 1777 buffer The string to be printed. 1778 stream Either "stdout" or "stderr". 1779 """ 1780 1781 if robot_env: 1782 BuiltIn().log_to_console(buffer, stream=stream, no_newline=True) 1783 else: 1784 if stream == "stdout": 1785 sys.stdout.write(buffer) 1786 sys.stdout.flush() 1787 else: 1788 sys.stderr.write(buffer) 1789 sys.stderr.flush() 1790 1791 1792def gp_log(buffer): 1793 r""" 1794 Log the buffer using either python logging or BuiltIn().log depending on 1795 whether we are running in a robot environment. 1796 1797 This function is intended for use only by other functions in this module. 1798 1799 Description of argument(s): 1800 buffer The string to be logged. 1801 """ 1802 1803 if robot_env: 1804 BuiltIn().log(buffer) 1805 else: 1806 logging.warning(buffer) 1807 1808 1809def gp_debug_print(buffer): 1810 r""" 1811 Print with gp_print only if gen_print_debug is set. 1812 1813 This function is intended for use only by other functions in this module. 1814 1815 Description of argument(s): 1816 buffer The string to be printed. 1817 """ 1818 1819 if not gen_print_debug: 1820 return 1821 1822 gp_print(buffer) 1823 1824 1825def get_var_value(var_value=None, 1826 default=1, 1827 var_name=None): 1828 r""" 1829 Return either var_value, the corresponding global value or default. 1830 1831 If var_value is not None, it will simply be returned. 1832 1833 If var_value is None, this function will return the corresponding global 1834 value of the variable in question. 1835 1836 Note: For global values, if we are in a robot environment, 1837 get_variable_value will be used. Otherwise, the __builtin__ version of 1838 the variable is returned (which are set by gen_arg.py functions). 1839 1840 If there is no global value associated with the variable, default is 1841 returned. 1842 1843 This function is useful for other functions in setting default values for 1844 parameters. 1845 1846 Example use: 1847 1848 def my_func(quiet=None): 1849 1850 quiet = int(get_var_value(quiet, 0)) 1851 1852 Example calls to my_func(): 1853 1854 In the following example, the caller is explicitly asking to have quiet be 1855 set to 1. 1856 1857 my_func(quiet=1) 1858 1859 In the following example, quiet will be set to the global value of quiet, 1860 if defined, or to 0 (the default). 1861 1862 my_func() 1863 1864 Description of argument(s): 1865 var_value The value to be returned (if not equal to 1866 None). 1867 default The value that is returned if var_value is 1868 None and there is no corresponding global 1869 value defined. 1870 var_name The name of the variable whose value is to 1871 be returned. Under most circumstances, 1872 this value need not be provided. This 1873 function can figure out the name of the 1874 variable passed as var_value. One 1875 exception to this would be if this 1876 function is called directly from a .robot 1877 file. 1878 """ 1879 1880 if var_value is not None: 1881 return var_value 1882 1883 if var_name is None: 1884 var_name = get_arg_name(None, 1, 2) 1885 1886 if robot_env: 1887 var_value = BuiltIn().get_variable_value("${" + var_name + "}", 1888 default) 1889 else: 1890 var_value = getattr(__builtin__, var_name, default) 1891 1892 return var_value 1893 1894 1895def get_stack_var(var_name, 1896 default="", 1897 init_stack_ix=2): 1898 r""" 1899 Starting with the caller's stack level, search upward in the call stack, 1900 for a variable named var_name and return its value. If the variable 1901 cannot be found, return default. 1902 1903 Example code: 1904 1905 def func12(): 1906 my_loc_var1 = get_stack_var('my_var1', "default value") 1907 1908 def func11(): 1909 my_var1 = 11 1910 func12() 1911 1912 In this example, get_stack_var will find the value of my_var1 in func11's 1913 stack and will therefore return the value 11. Therefore, my_loc_var1 1914 would get set to 11. 1915 1916 Description of argument(s): 1917 var_name The name of the variable to be searched 1918 for. 1919 default The value to return if the the variable 1920 cannot be found. 1921 init_stack_ix The initial stack index from which to 1922 begin the search. 0 would be the index of 1923 this func1tion ("get_stack_var"), 1 would 1924 be the index of the function calling this 1925 function, etc. 1926 """ 1927 1928 work_around_inspect_stack_cwd_failure() 1929 return next((frame[0].f_locals[var_name] 1930 for frame in inspect.stack()[init_stack_ix:] 1931 if var_name in frame[0].f_locals), default) 1932 1933 1934# hidden_text is a list of passwords which are to be replaced with asterisks 1935# by print functions defined in this module. 1936hidden_text = [] 1937# password_regex is created based on the contents of hidden_text. 1938password_regex = "" 1939 1940 1941def register_passwords(*args): 1942 r""" 1943 Register one or more passwords which are to be hidden in output produced 1944 by the print functions in this module. 1945 1946 Note: Blank password values are NOT registered. They are simply ignored. 1947 1948 Description of argument(s): 1949 args One or more password values. If a given 1950 password value is already registered, this 1951 function will simply do nothing. 1952 """ 1953 1954 global hidden_text 1955 global password_regex 1956 1957 for password in args: 1958 if password == "": 1959 break 1960 if password in hidden_text: 1961 break 1962 1963 # Place the password into the hidden_text list. 1964 hidden_text.append(password) 1965 # Create a corresponding password regular expression. Escape regex 1966 # special characters too. 1967 password_regex = '(' +\ 1968 '|'.join([re.escape(x) for x in hidden_text]) + ')' 1969 1970 1971def replace_passwords(buffer): 1972 r""" 1973 Return the buffer but with all registered passwords replaced by a string 1974 of asterisks. 1975 1976 1977 Description of argument(s): 1978 buffer The string to be returned but with 1979 passwords replaced. 1980 """ 1981 1982 global password_regex 1983 1984 if int(os.environ.get("DEBUG_SHOW_PASSWORDS", "0")): 1985 return buffer 1986 1987 if password_regex == "": 1988 # No passwords to replace. 1989 return buffer 1990 1991 return re.sub(password_regex, "********", buffer) 1992 1993 1994def create_print_wrapper_funcs(func_names, 1995 stderr_func_names, 1996 replace_dict, 1997 func_prefix=""): 1998 r""" 1999 Generate code for print wrapper functions and return the generated code as 2000 a string. 2001 2002 To illustrate, suppose there is a "print_foo_bar" function in the 2003 func_names list. 2004 This function will... 2005 - Expect that there is an sprint_foo_bar function already in existence. 2006 - Create a print_foo_bar function which calls sprint_foo_bar and prints 2007 the result. 2008 - Create a qprint_foo_bar function which calls upon sprint_foo_bar only if 2009 global value quiet is 0. 2010 - Create a dprint_foo_bar function which calls upon sprint_foo_bar only if 2011 global value debug is 1. 2012 2013 Also, code will be generated to define aliases for each function as well. 2014 Each alias will be created by replacing "print_" in the function name with 2015 "p" For example, the alias for print_foo_bar will be pfoo_bar. 2016 2017 Description of argument(s): 2018 func_names A list of functions for which print 2019 wrapper function code is to be generated. 2020 stderr_func_names A list of functions whose generated code 2021 should print to stderr rather than to 2022 stdout. 2023 replace_dict Please see the create_func_def_string 2024 function in wrap_utils.py for details on 2025 this parameter. This parameter will be 2026 passed directly to create_func_def_string. 2027 func_prefix Prefix to be pre-pended to the generated 2028 function name. 2029 """ 2030 2031 buffer = "" 2032 2033 for func_name in func_names: 2034 if func_name in stderr_func_names: 2035 replace_dict['output_stream'] = "stderr" 2036 else: 2037 replace_dict['output_stream'] = "stdout" 2038 2039 s_func_name = "s" + func_name 2040 q_func_name = "q" + func_name 2041 d_func_name = "d" + func_name 2042 2043 # We don't want to try to redefine the "print" function, thus the 2044 # following if statement. 2045 if func_name != "print": 2046 func_def = create_func_def_string(s_func_name, 2047 func_prefix + func_name, 2048 print_func_template, 2049 replace_dict) 2050 buffer += func_def 2051 2052 func_def = create_func_def_string(s_func_name, 2053 func_prefix + "q" + func_name, 2054 qprint_func_template, replace_dict) 2055 buffer += func_def 2056 2057 func_def = create_func_def_string(s_func_name, 2058 func_prefix + "d" + func_name, 2059 dprint_func_template, replace_dict) 2060 buffer += func_def 2061 2062 func_def = create_func_def_string(s_func_name, 2063 func_prefix + "l" + func_name, 2064 lprint_func_template, replace_dict) 2065 buffer += func_def 2066 2067 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var). 2068 alias = re.sub("print_", "p", func_name) 2069 alias = re.sub("print", "p", alias) 2070 prefixes = [func_prefix + "", "s", func_prefix + "q", 2071 func_prefix + "d", func_prefix + "l"] 2072 for prefix in prefixes: 2073 if alias == "p": 2074 continue 2075 func_def = prefix + alias + " = " + prefix + func_name 2076 buffer += func_def + "\n" 2077 2078 return buffer 2079 2080 2081# In the following section of code, we will dynamically create print versions 2082# for each of the sprint functions defined above. So, for example, where we 2083# have an sprint_time() function defined above that returns the time to the 2084# caller in a string, we will create a corresponding print_time() function 2085# that will print that string directly to stdout. 2086 2087# It can be complicated to follow what's being created below. Here is an 2088# example of the print_time() function that will be created: 2089 2090# def print_time(buffer=''): 2091# gp_print(replace_passwords(sprint_time(buffer=buffer)), stream='stdout') 2092 2093# For each print function defined below, there will also be a qprint, a 2094# dprint and an lprint version defined (e.g. qprint_time, dprint_time, 2095# lprint_time). 2096 2097# The q version of each print function will only print if the quiet variable 2098# is 0. 2099# The d version of each print function will only print if the debug variable 2100# is 1. 2101# The l version of each print function will print the contents as log data. 2102# For conventional programs, this means use of the logging module. For robot 2103# programs it means use of the BuiltIn().log() function. 2104 2105# Templates for the various print wrapper functions. 2106print_func_template = \ 2107 [ 2108 " <mod_qualifier>gp_print(<mod_qualifier>replace_passwords(" 2109 + "<call_line>), stream='<output_stream>')" 2110 ] 2111 2112qprint_func_template = \ 2113 [ 2114 " quiet_default = <mod_qualifier>get_var_value(None, 0, \"quiet\")", 2115 " quiet = <mod_qualifier>get_stack_var(\"quiet\", quiet_default)", 2116 " if int(quiet): return" 2117 ] + print_func_template 2118 2119dprint_func_template = \ 2120 [ 2121 " debug_default = <mod_qualifier>get_var_value(None, 0, \"debug\")", 2122 " debug = <mod_qualifier>get_stack_var(\"debug\", debug_default)", 2123 " if not int(debug): return" 2124 ] + print_func_template 2125 2126lprint_func_template = \ 2127 [ 2128 " <mod_qualifier>set_last_seconds_ix(<mod_qualifier>" 2129 + "lprint_last_seconds_ix())", 2130 " <mod_qualifier>gp_log(<mod_qualifier>replace_passwords" 2131 + "(<call_line>))", 2132 " <mod_qualifier>set_last_seconds_ix(<mod_qualifier>" 2133 + "standard_print_last_seconds_ix())" 2134 ] 2135 2136replace_dict = {'output_stream': 'stdout', 'mod_qualifier': ''} 2137 2138gp_debug_print("robot_env: " + str(robot_env) + "\n") 2139 2140# func_names contains a list of all print functions which should be created 2141# from their sprint counterparts. 2142func_names = ['print_time', 'print_timen', 'print_error', 'print_varx', 2143 'print_var', 'print_vars', 'print_dashes', 'indent', 2144 'print_call_stack', 'print_func_name', 'print_executing', 2145 'print_pgm_header', 'print_issuing', 'print_pgm_footer', 2146 'print_error_report', 'print', 'printn'] 2147 2148# stderr_func_names is a list of functions whose output should go to stderr 2149# rather than stdout. 2150stderr_func_names = ['print_error', 'print_error_report'] 2151 2152func_defs = create_print_wrapper_funcs(func_names, stderr_func_names, 2153 replace_dict) 2154gp_debug_print(func_defs) 2155exec(func_defs) 2156