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 is_dict(var_value): 773 r""" 774 Return non-zero if var_value is a type of dictionary and 0 if it is not. 775 776 The specific non-zero value returned will indicate what type of dictionary 777 var_value is (see constant functions above). 778 779 Description of argument(s): 780 var_value The object to be analyzed to determine 781 whether it is a dictionary and if so, what 782 type of dictionary. 783 """ 784 785 type_is_dict = 0 786 if isinstance(var_value, dict): 787 type_is_dict = dict_type() 788 try: 789 if isinstance(var_value, collections.OrderedDict): 790 type_is_dict = ordered_dict_type() 791 except AttributeError: 792 pass 793 try: 794 if isinstance(var_value, DotDict): 795 type_is_dict = dot_dict_type() 796 except NameError: 797 pass 798 try: 799 if isinstance(var_value, NormalizedDict): 800 type_is_dict = normalized_dict_type() 801 except NameError: 802 pass 803 return type_is_dict 804 805 806def get_int_types(): 807 r""" 808 Return a tuple consisting of the valid integer data types for the system 809 and version of python being run. 810 811 Example: 812 (int, long) 813 """ 814 815 try: 816 int_types = (int, long) 817 except NameError: 818 int_types = (int,) 819 return int_types 820 821 822def get_string_types(): 823 r""" 824 Return a tuple consisting of the valid string data types for the system 825 and version of python being run. 826 827 Example: 828 (str, unicode) 829 """ 830 831 try: 832 string_types = (str, unicode) 833 except NameError: 834 string_types = (bytes, str) 835 return string_types 836 837 838def valid_fmts(): 839 r""" 840 Return a list of the valid formats that can be specified for the fmt 841 argument of the sprint_varx function (defined below). 842 """ 843 844 return [ 845 'hexa', 846 'octal', 847 'binary', 848 'blank', 849 'terse', 850 'quote_keys', 851 'show_type'] 852 853 854def create_fmt_definition(): 855 r""" 856 Create a string consisting of function-definition code that can be 857 executed to create constant fmt definition functions. 858 859 These functions can be used by callers of sprint_var/sprint_varx to set 860 the fmt argument correctly. 861 862 Likewise, the sprint_varx function will use these generated functions to 863 correctly interpret the fmt argument. 864 865 Example output from this function: 866 867 def hexa(): 868 return 0x00000001 869 def octal_fmt(): 870 return 0x00000002 871 etc. 872 """ 873 874 buffer = "" 875 bits = 0x00000001 876 for fmt_name in valid_fmts(): 877 buffer += "def " + fmt_name + "():\n" 878 buffer += " return " + "0x%08x" % bits + "\n" 879 bits = bits << 1 880 return buffer 881 882 883# Dynamically create fmt definitions (for use with the fmt argument of 884# sprint_varx function): 885exec(create_fmt_definition()) 886 887 888def list_pop(a_list, index=0, default=None): 889 r""" 890 Pop the list entry indicated by the index and return the entry. If no 891 such entry exists, return default. 892 893 Note that the list passed to this function will be modified. 894 895 Description of argument(s): 896 a_list The list from which an entry is to be 897 popped. 898 index The index indicating which entry is to be 899 popped. 900 default The value to be returned if there is no 901 entry at the given index location. 902 """ 903 try: 904 return a_list.pop(index) 905 except IndexError: 906 return default 907 908 909def parse_fmt(fmt): 910 r""" 911 Parse the fmt argument and return a tuple consisting of a format and a 912 child format. 913 914 This function was written for use by the sprint_varx function defined in 915 this module. 916 917 When sprint_varx is processing a multi-level object such as a list or 918 dictionary (which in turn may contain other lists or dictionaries), it 919 will use the fmt value to dictate the print formatting of the current 920 level and the child_fmt value to dictate the print formatting of 921 subordinate levels. Consider the following example: 922 923 python code example: 924 925 ord_dict = \ 926 collections.OrderedDict([ 927 ('one', 1), 928 ('two', 2), 929 ('sub', 930 collections.OrderedDict([ 931 ('three', 3), ('four', 4)]))]) 932 933 print_var(ord_dict) 934 935 This would generate the following output: 936 937 ord_dict: 938 ord_dict[one]: 1 939 ord_dict[two]: 2 940 ord_dict[sub]: 941 ord_dict[sub][three]: 3 942 ord_dict[sub][four]: 4 943 944 The first level in this example is the line that simply says "ord_dict". 945 The second level is comprised of the dictionary entries with the keys 946 'one', 'two' and 'sub'. The third level is comprised of the last 2 lines 947 (i.e. printed values 3 and 4). 948 949 Given the data structure shown above, the programmer could code the 950 following where fmt is a simple integer value set by calling the terse() 951 function. 952 953 print_var(ord_dict, fmt=terse()) 954 955 The output would look like this: 956 957 ord_dict: 958 [one]: 1 959 [two]: 2 960 [sub]: 961 [three]: 3 962 [four]: 4 963 964 Note the terse format where the name of the object ("ord_dict") is not 965 repeated on every line as it was in example #1. 966 967 If the programmer wishes to get more granular with the fmt argument, 968 he/she can specify it as a list where each entry corresponds to a level of 969 the object being printed. The last such list entry governs the print 970 formatting of all subordinate parts of the given object. 971 972 Look at each of the following code examples and their corresponding 973 output. See how the show_type() formatting affects the printing depending 974 on which position it occupies in the fmt list argument: 975 976 print_var(ord_dict, fmt=[show_type()]) 977 978 ord_dict: <collections.OrderedDict> 979 ord_dict[one]: 1 <int> 980 ord_dict[two]: 2 <int> 981 ord_dict[sub]: <collections.OrderedDict> 982 ord_dict[sub][three]: 3 <int> 983 ord_dict[sub][four]: 4 <int> 984 985 print_var(ord_dict, fmt=[0, show_type()]) 986 987 ord_dict: 988 ord_dict[one]: 1 <int> 989 ord_dict[two]: 2 <int> 990 ord_dict[sub]: <collections.OrderedDict> 991 ord_dict[sub][three]: 3 <int> 992 ord_dict[sub][four]: 4 <int> 993 994 print_var(ord_dict, fmt=[0, 0, show_type()]) 995 996 ord_dict: 997 ord_dict[one]: 1 998 ord_dict[two]: 2 999 ord_dict[sub]: 1000 ord_dict[sub][three]: 3 <int> 1001 ord_dict[sub][four]: 4 <int> 1002 1003 Description of argument(s): 1004 fmt The format argument such as is passed to 1005 sprint_varx. This argument may be an 1006 integer or a list of integers. See the 1007 prolog of sprint_varx for more details. 1008 """ 1009 1010 # Make a deep copy of the fmt argument in order to avoid modifying the 1011 # caller's fmt value when it is a list. 1012 fmt = copy.deepcopy(fmt) 1013 try: 1014 # Assume fmt is a list. Pop the first element from the list. 1015 first_element = list_pop(fmt, index=0, default=0) 1016 # Return the first list element along with either 1) the remainder of 1017 # the fmt list if not null or 2) another copy of the first element. 1018 return first_element, fmt if len(fmt) else first_element 1019 except AttributeError: 1020 # fmt is not a list so treat it as a simple integer value. 1021 return fmt, fmt 1022 1023 1024def sprint_varx(var_name, 1025 var_value, 1026 fmt=0, 1027 indent=dft_indent, 1028 col1_width=dft_col1_width, 1029 trailing_char="\n", 1030 key_list=None, 1031 delim=":"): 1032 r""" 1033 Print the var name/value passed to it. If the caller lets col1_width 1034 default, the printing lines up nicely with output generated by the 1035 print_time functions. 1036 1037 Note that the sprint_var function (defined below) can be used to call this 1038 function so that the programmer does not need to pass the var_name. 1039 sprint_var will figure out the var_name. The sprint_var function is the 1040 one that would normally be used by the general user. 1041 1042 For example, the following python code: 1043 1044 first_name = "Mike" 1045 print_time("Doing this...\n") 1046 print_varx("first_name", first_name) 1047 print_time("Doing that...\n") 1048 1049 Will generate output like this: 1050 1051 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this... 1052 first_name: Mike 1053 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that... 1054 1055 This function recognizes several complex types of data such as dict, list 1056 or tuple. 1057 1058 For example, the following python code: 1059 1060 my_dict = dict(one=1, two=2, three=3) 1061 print_var(my_dict) 1062 1063 Will generate the following output: 1064 1065 my_dict: 1066 my_dict[three]: 3 1067 my_dict[two]: 2 1068 my_dict[one]: 1 1069 1070 Description of argument(s). 1071 var_name The name of the variable to be printed. 1072 var_value The value of the variable to be printed. 1073 fmt A bit map to dictate the format of the 1074 output. For printing multi-level objects 1075 like lists and dictionaries, this argument 1076 may also be a list of bit maps. The first 1077 list element pertains to the highest level 1078 of output, the second element pertains to 1079 the 2nd level of output, etc. The last 1080 element in the list pertains to all 1081 subordinate levels. The bits can be set 1082 using the dynamically created functionhs 1083 above. Example: sprint_varx("var1", var1, 1084 fmt=terse()). Note that these values can 1085 be OR'ed together: print_var(var1, hexa() 1086 | terse()). If the caller ORs mutually 1087 exclusive bits (hexa() | octal()), 1088 behavior is not guaranteed. The following 1089 features are supported: 1090 hexa Print all integer values in hexadecimal 1091 format. 1092 octal Print all integer values in octal format. 1093 binary Print all integer values in binary format. 1094 blank For blank string values, print "<blank>" 1095 instead of an actual blank. 1096 terse For structured values like dictionaries, 1097 lists, etc. do not repeat the name of the 1098 variable on each line to the right of the 1099 key or subscript value. Example: print 1100 "[key1]" instead of "my_dict[key1]". 1101 quote_keys Quote dictionary keys in the output. 1102 Example: my_dict['key1'] instead of 1103 my_dict[key1]. 1104 show_type Show the type of the data in angled 1105 brackets just to the right of the data. 1106 indent The number of spaces to indent the output. 1107 col1_width The width of the output column containing 1108 the variable name. The default value of 1109 this is adjusted so that the var_value 1110 lines up with text printed via the 1111 print_time function. 1112 trailing_char The character to be used at the end of the 1113 returned string. The default value is a 1114 line feed. 1115 key_list A list of which dictionary keys should be 1116 printed. All others keys will be skipped. 1117 Each value in key_list will be regarded 1118 as a regular expression and it will be 1119 regarded as anchored to the beginning and 1120 ends of the dictionary key being 1121 referenced. For example if key_list is 1122 ["one", "two"], the resulting regex used 1123 will be "^one|two$", i.e. only keys "one" 1124 and "two" from the var_value dictionary 1125 will be printed. As another example, if 1126 the caller were to specify a key_list of 1127 ["one.*"], then only dictionary keys whose 1128 names begin with "one" will be printed. 1129 Note: This argument pertains only to 1130 var_values which are dictionaries. 1131 delim The value to be used to delimit the 1132 variable name from the variable value in 1133 the output. 1134 """ 1135 1136 fmt, child_fmt = parse_fmt(fmt) 1137 1138 if fmt & show_type(): 1139 type_str = "<" + str(type(var_value)).split("'")[1] + ">" 1140 # Compose object type categories. 1141 int_types = get_int_types() 1142 string_types = get_string_types() 1143 simple_types = int_types + string_types + (float, bool, type, type(None)) 1144 # Determine the type. 1145 if type(var_value) in simple_types: 1146 # The data type is simple in the sense that it has no subordinate 1147 # parts. 1148 # Adjust col1_width. 1149 col1_width = col1_width - indent 1150 # Set default value for value_format. 1151 value_format = "%s" 1152 # Process format requests. 1153 if type(var_value) in int_types: 1154 # Process format values pertaining to int types. 1155 if fmt & hexa(): 1156 num_hex_digits = max(dft_num_hex_digits(), 1157 get_req_num_hex_digits(var_value)) 1158 # Convert a negative number to its positive twos complement 1159 # for proper printing. For example, instead of printing -1 as 1160 # "0x-000000000000001" it will be printed as 1161 # "0xffffffffffffffff". 1162 var_value = var_value & (2 ** (num_hex_digits * 4) - 1) 1163 value_format = "0x%0" + str(num_hex_digits) + "x" 1164 elif fmt & octal(): 1165 value_format = "0o%016o" 1166 elif fmt & binary(): 1167 num_digits, remainder = \ 1168 divmod(max(bit_length(var_value), 1), 8) 1169 num_digits *= 8 1170 if remainder: 1171 num_digits += 8 1172 num_digits += 2 1173 value_format = '#0' + str(num_digits) + 'b' 1174 var_value = format(var_value, value_format) 1175 value_format = "%s" 1176 elif type(var_value) in string_types: 1177 # Process format values pertaining to string types. 1178 if fmt & blank() and var_value == "": 1179 value_format = "%s" 1180 var_value = "<blank>" 1181 elif type(var_value) is type: 1182 var_value = str(var_value).split("'")[1] 1183 format_string = "%" + str(indent) + "s%-" + str(col1_width) + "s" \ 1184 + value_format 1185 if fmt & show_type(): 1186 if var_value != "": 1187 format_string += " " 1188 format_string += type_str 1189 format_string += trailing_char 1190 if fmt & terse(): 1191 # Strip everything leading up to the first left square brace. 1192 var_name = re.sub(r".*\[", "[", var_name) 1193 if value_format == "0x%08x": 1194 return format_string % ("", str(var_name) + delim, 1195 var_value & 0xffffffff) 1196 else: 1197 return format_string % ("", str(var_name) + delim, var_value) 1198 else: 1199 # The data type is complex in the sense that it has subordinate parts. 1200 if fmt & terse(): 1201 # Strip everything leading up to the first square brace. 1202 loc_var_name = re.sub(r".*\[", "[", var_name) 1203 else: 1204 loc_var_name = var_name 1205 format_string = "%" + str(indent) + "s%s\n" 1206 buffer = format_string % ("", loc_var_name + ":") 1207 if fmt & show_type(): 1208 buffer = buffer.replace("\n", " " + type_str + "\n") 1209 indent += 2 1210 try: 1211 length = len(var_value) 1212 except TypeError: 1213 length = 0 1214 ix = 0 1215 loc_trailing_char = "\n" 1216 if is_dict(var_value): 1217 if type(child_fmt) is list: 1218 child_quote_keys = (child_fmt[0] & quote_keys()) 1219 else: 1220 child_quote_keys = (child_fmt & quote_keys()) 1221 for key, value in var_value.items(): 1222 if key_list is not None: 1223 key_list_regex = "^" + "|".join(key_list) + "$" 1224 if not re.match(key_list_regex, key): 1225 continue 1226 ix += 1 1227 if ix == length: 1228 loc_trailing_char = trailing_char 1229 if child_quote_keys: 1230 key = "'" + key + "'" 1231 key = "[" + str(key) + "]" 1232 buffer += sprint_varx(var_name + key, value, child_fmt, indent, 1233 col1_width, loc_trailing_char, key_list) 1234 elif type(var_value) in (list, tuple, set): 1235 for key, value in enumerate(var_value): 1236 ix += 1 1237 if ix == length: 1238 loc_trailing_char = trailing_char 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 isinstance(var_value, argparse.Namespace): 1243 for key in var_value.__dict__: 1244 ix += 1 1245 if ix == length: 1246 loc_trailing_char = trailing_char 1247 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \ 1248 + ", var_value." + key + ", child_fmt, indent," \ 1249 + " col1_width, loc_trailing_char, key_list)" 1250 exec(cmd_buf) 1251 else: 1252 var_type = type(var_value).__name__ 1253 func_name = sys._getframe().f_code.co_name 1254 var_value = "<" + var_type + " type not supported by " + \ 1255 func_name + "()>" 1256 value_format = "%s" 1257 indent -= 2 1258 # Adjust col1_width. 1259 col1_width = col1_width - indent 1260 format_string = "%" + str(indent) + "s%-" \ 1261 + str(col1_width) + "s" + value_format + trailing_char 1262 return format_string % ("", str(var_name) + ":", var_value) 1263 1264 return buffer 1265 1266 return "" 1267 1268 1269def sprint_var(*args, **kwargs): 1270 r""" 1271 Figure out the name of the first argument for the caller and then call 1272 sprint_varx with it. Therefore, the following 2 calls are equivalent: 1273 sprint_varx("var1", var1) 1274 sprint_var(var1) 1275 1276 See sprint_varx for description of arguments. 1277 """ 1278 1279 stack_frame = 2 1280 caller_func_name = sprint_func_name(2) 1281 if caller_func_name.endswith("print_var"): 1282 stack_frame += 1 1283 # Get the name of the first variable passed to this function. 1284 var_name = get_arg_name(None, 1, stack_frame) 1285 return sprint_varx(var_name, *args, **kwargs) 1286 1287 1288def sprint_vars(*args, **kwargs): 1289 r""" 1290 Sprint the values of one or more variables. 1291 1292 Description of argument(s): 1293 args The variable values which are to be 1294 printed. 1295 kwargs See sprint_varx (above) for description of 1296 additional arguments. 1297 """ 1298 1299 stack_frame = 2 1300 caller_func_name = sprint_func_name(2) 1301 if caller_func_name.endswith("print_vars"): 1302 stack_frame += 1 1303 1304 buffer = "" 1305 arg_num = 1 1306 for var_value in args: 1307 var_name = get_arg_name(None, arg_num, stack_frame) 1308 buffer += sprint_varx(var_name, var_value, **kwargs) 1309 arg_num += 1 1310 1311 return buffer 1312 1313 1314def sprint_dashes(indent=dft_indent, 1315 width=80, 1316 line_feed=1, 1317 char="-"): 1318 r""" 1319 Return a string of dashes to the caller. 1320 1321 Description of argument(s): 1322 indent The number of characters to indent the 1323 output. 1324 width The width of the string of dashes. 1325 line_feed Indicates whether the output should end 1326 with a line feed. 1327 char The character to be repeated in the output 1328 string. 1329 """ 1330 1331 width = int(width) 1332 buffer = " " * int(indent) + char * width 1333 if line_feed: 1334 buffer += "\n" 1335 1336 return buffer 1337 1338 1339def sindent(text="", 1340 indent=0): 1341 r""" 1342 Pre-pend the specified number of characters to the text string (i.e. 1343 indent it) and return it. 1344 1345 Description of argument(s): 1346 text The string to be indented. 1347 indent The number of characters to indent the 1348 string. 1349 """ 1350 1351 format_string = "%" + str(indent) + "s%s" 1352 buffer = format_string % ("", text) 1353 1354 return buffer 1355 1356 1357func_line_style_std = None 1358func_line_style_short = 1 1359 1360 1361def sprint_func_line(stack_frame, style=None): 1362 r""" 1363 For the given stack_frame, return a formatted string containing the 1364 function name and all its arguments. 1365 1366 Example: 1367 1368 func1(last_name = 'walsh', first_name = 'mikey') 1369 1370 Description of argument(s): 1371 stack_frame A stack frame (such as is returned by 1372 inspect.stack()). 1373 style Indicates the style or formatting of the 1374 result string. Acceptable values are 1375 shown above. 1376 1377 Description of styles: 1378 func_line_style_std The standard formatting. 1379 func_line_style_short 1) The self parm (associated with methods) 1380 will be dropped. 2) The args and kwargs 1381 values will be treated as special. In 1382 both cases the arg name ('args' or 1383 'kwargs') will be dropped and only the 1384 values will be shown. 1385 """ 1386 1387 func_name = str(stack_frame[3]) 1388 if func_name == "?": 1389 # "?" is the name used when code is not in a function. 1390 func_name = "(none)" 1391 1392 if func_name == "<module>": 1393 # If the func_name is the "main" program, we simply get the command 1394 # line call string. 1395 func_and_args = ' '.join(sys.argv) 1396 else: 1397 # Get the program arguments. 1398 (args, varargs, keywords, locals) =\ 1399 inspect.getargvalues(stack_frame[0]) 1400 1401 args_list = [] 1402 for arg_name in filter(None, args + [varargs, keywords]): 1403 # Get the arg value from frame locals. 1404 arg_value = locals[arg_name] 1405 if arg_name == 'self': 1406 if style == func_line_style_short: 1407 continue 1408 # Manipulations to improve output for class methods. 1409 func_name = arg_value.__class__.__name__ + "." + func_name 1410 args_list.append(arg_name + " = <self>") 1411 elif (style == func_line_style_short 1412 and arg_name == 'args' 1413 and type(arg_value) in (list, tuple)): 1414 if len(arg_value) == 0: 1415 continue 1416 args_list.append(repr(', '.join(arg_value))) 1417 elif (style == func_line_style_short 1418 and arg_name == 'kwargs' 1419 and type(arg_value) is dict): 1420 for key, value in arg_value.items(): 1421 args_list.append(key + "=" + repr(value)) 1422 else: 1423 args_list.append(arg_name + " = " + repr(arg_value)) 1424 args_str = "(" + ', '.join(map(str, args_list)) + ")" 1425 1426 # Now we need to print this in a nicely-wrapped way. 1427 func_and_args = func_name + args_str 1428 1429 return func_and_args 1430 1431 1432def sprint_call_stack(indent=0, 1433 stack_frame_ix=0, 1434 style=None): 1435 r""" 1436 Return a call stack report for the given point in the program with line 1437 numbers, function names and function parameters and arguments. 1438 1439 Sample output: 1440 1441 ------------------------------------------------------------------------- 1442 Python function call stack 1443 1444 Line # Function name and arguments 1445 ------ ------------------------------------------------------------------ 1446 424 sprint_call_stack() 1447 4 print_call_stack() 1448 31 func1(last_name = 'walsh', first_name = 'mikey') 1449 59 /tmp/scr5.py 1450 ------------------------------------------------------------------------- 1451 1452 Description of argument(s): 1453 indent The number of characters to indent each 1454 line of output. 1455 stack_frame_ix The index of the first stack frame which 1456 is to be returned. 1457 style See the sprint_line_func prolog above for 1458 details. 1459 """ 1460 1461 buffer = "" 1462 buffer += sprint_dashes(indent) 1463 buffer += sindent("Python function call stack\n\n", indent) 1464 buffer += sindent("Line # Function name and arguments\n", indent) 1465 buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73) 1466 1467 # Grab the current program stack. 1468 work_around_inspect_stack_cwd_failure() 1469 current_stack = inspect.stack() 1470 1471 # Process each frame in turn. 1472 format_string = "%6s %s\n" 1473 ix = 0 1474 for stack_frame in current_stack: 1475 if ix < stack_frame_ix: 1476 ix += 1 1477 continue 1478 # Make the line number shown to be the line where one finds the line 1479 # shown. 1480 try: 1481 line_num = str(current_stack[ix + 1][2]) 1482 except IndexError: 1483 line_num = "" 1484 func_and_args = sprint_func_line(stack_frame, style=style) 1485 1486 buffer += sindent(format_string % (line_num, func_and_args), indent) 1487 ix += 1 1488 1489 buffer += sprint_dashes(indent) 1490 1491 return buffer 1492 1493 1494def sprint_executing(stack_frame_ix=None, style=None): 1495 r""" 1496 Print a line indicating what function is executing and with what parameter 1497 values. This is useful for debugging. 1498 1499 Sample output: 1500 1501 #(CDT) 2016/08/25 17:54:27 - Executing: func1(x = 1) 1502 1503 Description of argument(s): 1504 stack_frame_ix The index of the stack frame whose 1505 function info should be returned. If the 1506 caller does not specify a value, this 1507 function will set the value to 1 which is 1508 the index of the caller's stack frame. If 1509 the caller is the wrapper function 1510 "print_executing", this function will bump 1511 it up by 1. 1512 style See the sprint_line_func prolog above for 1513 details. 1514 """ 1515 1516 # If user wants default stack_frame_ix. 1517 if stack_frame_ix is None: 1518 func_name = sys._getframe().f_code.co_name 1519 caller_func_name = sys._getframe(1).f_code.co_name 1520 if caller_func_name.endswith(func_name[1:]): 1521 stack_frame_ix = 2 1522 else: 1523 stack_frame_ix = 1 1524 1525 work_around_inspect_stack_cwd_failure() 1526 stack_frame = inspect.stack()[stack_frame_ix] 1527 1528 func_and_args = sprint_func_line(stack_frame, style) 1529 1530 return sprint_time() + "Executing: " + func_and_args + "\n" 1531 1532 1533def sprint_pgm_header(indent=0, 1534 linefeed=1): 1535 r""" 1536 Return a standardized header that programs should print at the beginning 1537 of the run. It includes useful information like command line, pid, 1538 userid, program parameters, etc. 1539 1540 Description of argument(s): 1541 indent The number of characters to indent each 1542 line of output. 1543 linefeed Indicates whether a line feed be included 1544 at the beginning and end of the report. 1545 """ 1546 1547 col1_width = dft_col1_width + indent 1548 1549 buffer = "" 1550 if linefeed: 1551 buffer = "\n" 1552 1553 if robot_env: 1554 suite_name = BuiltIn().get_variable_value("${suite_name}") 1555 buffer += sindent(sprint_time("Running test suite \"" + suite_name 1556 + "\".\n"), indent) 1557 1558 buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent) 1559 buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n", 1560 indent) 1561 buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent, 1562 col1_width) 1563 # We want the output to show a customized name for the pid and pgid but 1564 # we want it to look like a valid variable name. Therefore, we'll use 1565 # pgm_name_var_name which was set when this module was imported. 1566 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent, 1567 col1_width) 1568 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent, 1569 col1_width) 1570 userid_num = str(os.geteuid()) 1571 try: 1572 username = os.getlogin() 1573 except OSError: 1574 if userid_num == "0": 1575 username = "root" 1576 else: 1577 username = "?" 1578 buffer += sprint_varx("uid", userid_num + " (" + username 1579 + ")", 0, indent, col1_width) 1580 buffer += sprint_varx("gid", str(os.getgid()) + " (" 1581 + str(grp.getgrgid(os.getgid()).gr_name) + ")", 0, 1582 indent, col1_width) 1583 buffer += sprint_varx("host_name", socket.gethostname(), 0, indent, 1584 col1_width) 1585 try: 1586 DISPLAY = os.environ['DISPLAY'] 1587 except KeyError: 1588 DISPLAY = "" 1589 buffer += sprint_var(DISPLAY, 0, indent, 1590 col1_width) 1591 # TODO: Add code to print caller's parms. 1592 1593 # __builtin__.arg_obj is created by the get_arg module function, 1594 # gen_get_options. 1595 try: 1596 buffer += ga.sprint_args(__builtin__.arg_obj, indent) 1597 except AttributeError: 1598 pass 1599 1600 if robot_env: 1601 # Get value of global parm_list. 1602 parm_list = BuiltIn().get_variable_value("${parm_list}") 1603 1604 for parm in parm_list: 1605 parm_value = BuiltIn().get_variable_value("${" + parm + "}") 1606 buffer += sprint_varx(parm, parm_value, 0, indent, col1_width) 1607 1608 # Setting global program_pid. 1609 BuiltIn().set_global_variable("${program_pid}", os.getpid()) 1610 1611 if linefeed: 1612 buffer += "\n" 1613 1614 return buffer 1615 1616 1617def sprint_error_report(error_text="\n", 1618 indent=2, 1619 format=None): 1620 r""" 1621 Return a string with a standardized report which includes the caller's 1622 error text, the call stack and the program header. 1623 1624 Description of argument(s): 1625 error_text The error text to be included in the 1626 report. The caller should include any 1627 needed linefeeds. 1628 indent The number of characters to indent each 1629 line of output. 1630 format Long or short format. Long includes 1631 extras like lines of dashes, call stack, 1632 etc. 1633 """ 1634 1635 # Process input. 1636 indent = int(indent) 1637 if format is None: 1638 if robot_env: 1639 format = 'short' 1640 else: 1641 format = 'long' 1642 error_text = error_text.rstrip('\n') + '\n' 1643 1644 if format == 'short': 1645 return sprint_error(error_text) 1646 1647 buffer = "" 1648 buffer += sprint_dashes(width=120, char="=") 1649 buffer += sprint_error(error_text) 1650 buffer += "\n" 1651 # Calling sprint_call_stack with stack_frame_ix of 0 causes it to show 1652 # itself and this function in the call stack. This is not helpful to a 1653 # debugger and is therefore clutter. We will adjust the stack_frame_ix to 1654 # hide that information. 1655 stack_frame_ix = 1 1656 caller_func_name = sprint_func_name(2) 1657 if caller_func_name.endswith("print_error_report"): 1658 stack_frame_ix += 1 1659 buffer += sprint_call_stack(indent, stack_frame_ix) 1660 buffer += sprint_pgm_header(indent) 1661 buffer += sprint_dashes(width=120, char="=") 1662 1663 return buffer 1664 1665 1666def sprint_issuing(cmd_buf, 1667 test_mode=0): 1668 r""" 1669 Return a line indicating a command that the program is about to execute. 1670 1671 Sample output for a cmd_buf of "ls" 1672 1673 #(CDT) 2016/08/25 17:57:36 - Issuing: ls 1674 1675 Description of argument(s): 1676 cmd_buf The command to be executed by caller. 1677 test_mode With test_mode set, the output will look 1678 like this: 1679 1680 #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls 1681 1682 """ 1683 1684 buffer = sprint_time() 1685 if test_mode: 1686 buffer += "(test_mode) " 1687 if type(cmd_buf) is list: 1688 # Assume this is a robot command in the form of a list. 1689 cmd_buf = ' '.join([str(element) for element in cmd_buf]) 1690 buffer += "Issuing: " + cmd_buf + "\n" 1691 1692 return buffer 1693 1694 1695def sprint_pgm_footer(): 1696 r""" 1697 Return a standardized footer that programs should print at the end of the 1698 program run. It includes useful information like total run time, etc. 1699 """ 1700 1701 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n" 1702 1703 total_time = time.time() - start_time 1704 total_time_string = "%0.6f" % total_time 1705 1706 buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string) 1707 buffer += "\n" 1708 1709 return buffer 1710 1711 1712def sprint(buffer=""): 1713 r""" 1714 Simply return the user's buffer. This function is used by the qprint and 1715 dprint functions defined dynamically below, i.e. it would not normally be 1716 called for general use. 1717 1718 Description of argument(s). 1719 buffer This will be returned to the caller. 1720 """ 1721 1722 try: 1723 return str(buffer) 1724 except UnicodeEncodeError: 1725 return buffer 1726 1727 1728def sprintn(buffer=""): 1729 r""" 1730 Simply return the user's buffer with a line feed. This function is used 1731 by the qprint and dprint functions defined dynamically below, i.e. it 1732 would not normally be called for general use. 1733 1734 Description of argument(s). 1735 buffer This will be returned to the caller. 1736 """ 1737 1738 try: 1739 buffer = str(buffer) + "\n" 1740 except UnicodeEncodeError: 1741 buffer = buffer + "\n" 1742 1743 return buffer 1744 1745 1746def gp_print(buffer, 1747 stream='stdout'): 1748 r""" 1749 Print the buffer using either sys.stdout.write or BuiltIn().log_to_console 1750 depending on whether we are running in a robot environment. 1751 1752 This function is intended for use only by other functions in this module. 1753 1754 Description of argument(s): 1755 buffer The string to be printed. 1756 stream Either "stdout" or "stderr". 1757 """ 1758 1759 if robot_env: 1760 BuiltIn().log_to_console(buffer, stream=stream, no_newline=True) 1761 else: 1762 if stream == "stdout": 1763 sys.stdout.write(buffer) 1764 sys.stdout.flush() 1765 else: 1766 sys.stderr.write(buffer) 1767 sys.stderr.flush() 1768 1769 1770def gp_log(buffer): 1771 r""" 1772 Log the buffer using either python logging or BuiltIn().log depending on 1773 whether we are running in a robot environment. 1774 1775 This function is intended for use only by other functions in this module. 1776 1777 Description of argument(s): 1778 buffer The string to be logged. 1779 """ 1780 1781 if robot_env: 1782 BuiltIn().log(buffer) 1783 else: 1784 logging.warning(buffer) 1785 1786 1787def gp_debug_print(buffer): 1788 r""" 1789 Print with gp_print only if gen_print_debug is set. 1790 1791 This function is intended for use only by other functions in this module. 1792 1793 Description of argument(s): 1794 buffer The string to be printed. 1795 """ 1796 1797 if not gen_print_debug: 1798 return 1799 1800 gp_print(buffer) 1801 1802 1803def get_var_value(var_value=None, 1804 default=1, 1805 var_name=None): 1806 r""" 1807 Return either var_value, the corresponding global value or default. 1808 1809 If var_value is not None, it will simply be returned. 1810 1811 If var_value is None, this function will return the corresponding global 1812 value of the variable in question. 1813 1814 Note: For global values, if we are in a robot environment, 1815 get_variable_value will be used. Otherwise, the __builtin__ version of 1816 the variable is returned (which are set by gen_arg.py functions). 1817 1818 If there is no global value associated with the variable, default is 1819 returned. 1820 1821 This function is useful for other functions in setting default values for 1822 parameters. 1823 1824 Example use: 1825 1826 def my_func(quiet=None): 1827 1828 quiet = int(get_var_value(quiet, 0)) 1829 1830 Example calls to my_func(): 1831 1832 In the following example, the caller is explicitly asking to have quiet be 1833 set to 1. 1834 1835 my_func(quiet=1) 1836 1837 In the following example, quiet will be set to the global value of quiet, 1838 if defined, or to 0 (the default). 1839 1840 my_func() 1841 1842 Description of argument(s): 1843 var_value The value to be returned (if not equal to 1844 None). 1845 default The value that is returned if var_value is 1846 None and there is no corresponding global 1847 value defined. 1848 var_name The name of the variable whose value is to 1849 be returned. Under most circumstances, 1850 this value need not be provided. This 1851 function can figure out the name of the 1852 variable passed as var_value. One 1853 exception to this would be if this 1854 function is called directly from a .robot 1855 file. 1856 """ 1857 1858 if var_value is not None: 1859 return var_value 1860 1861 if var_name is None: 1862 var_name = get_arg_name(None, 1, 2) 1863 1864 if robot_env: 1865 var_value = BuiltIn().get_variable_value("${" + var_name + "}", 1866 default) 1867 else: 1868 var_value = getattr(__builtin__, var_name, default) 1869 1870 return var_value 1871 1872 1873def get_stack_var(var_name, 1874 default="", 1875 init_stack_ix=2): 1876 r""" 1877 Starting with the caller's stack level, search upward in the call stack, 1878 for a variable named var_name and return its value. If the variable 1879 cannot be found, return default. 1880 1881 Example code: 1882 1883 def func12(): 1884 my_loc_var1 = get_stack_var('my_var1', "default value") 1885 1886 def func11(): 1887 my_var1 = 11 1888 func12() 1889 1890 In this example, get_stack_var will find the value of my_var1 in func11's 1891 stack and will therefore return the value 11. Therefore, my_loc_var1 1892 would get set to 11. 1893 1894 Description of argument(s): 1895 var_name The name of the variable to be searched 1896 for. 1897 default The value to return if the the variable 1898 cannot be found. 1899 init_stack_ix The initial stack index from which to 1900 begin the search. 0 would be the index of 1901 this func1tion ("get_stack_var"), 1 would 1902 be the index of the function calling this 1903 function, etc. 1904 """ 1905 1906 work_around_inspect_stack_cwd_failure() 1907 return next((frame[0].f_locals[var_name] 1908 for frame in inspect.stack()[init_stack_ix:] 1909 if var_name in frame[0].f_locals), default) 1910 1911 1912# hidden_text is a list of passwords which are to be replaced with asterisks 1913# by print functions defined in this module. 1914hidden_text = [] 1915# password_regex is created based on the contents of hidden_text. 1916password_regex = "" 1917 1918 1919def register_passwords(*args): 1920 r""" 1921 Register one or more passwords which are to be hidden in output produced 1922 by the print functions in this module. 1923 1924 Note: Blank password values are NOT registered. They are simply ignored. 1925 1926 Description of argument(s): 1927 args One or more password values. If a given 1928 password value is already registered, this 1929 function will simply do nothing. 1930 """ 1931 1932 global hidden_text 1933 global password_regex 1934 1935 for password in args: 1936 if password == "": 1937 break 1938 if password in hidden_text: 1939 break 1940 1941 # Place the password into the hidden_text list. 1942 hidden_text.append(password) 1943 # Create a corresponding password regular expression. Escape regex 1944 # special characters too. 1945 password_regex = '(' +\ 1946 '|'.join([re.escape(x) for x in hidden_text]) + ')' 1947 1948 1949def replace_passwords(buffer): 1950 r""" 1951 Return the buffer but with all registered passwords replaced by a string 1952 of asterisks. 1953 1954 1955 Description of argument(s): 1956 buffer The string to be returned but with 1957 passwords replaced. 1958 """ 1959 1960 global password_regex 1961 1962 if int(os.environ.get("DEBUG_SHOW_PASSWORDS", "0")): 1963 return buffer 1964 1965 if password_regex == "": 1966 # No passwords to replace. 1967 return buffer 1968 1969 return re.sub(password_regex, "********", buffer) 1970 1971 1972def create_print_wrapper_funcs(func_names, 1973 stderr_func_names, 1974 replace_dict, 1975 func_prefix=""): 1976 r""" 1977 Generate code for print wrapper functions and return the generated code as 1978 a string. 1979 1980 To illustrate, suppose there is a "print_foo_bar" function in the 1981 func_names list. 1982 This function will... 1983 - Expect that there is an sprint_foo_bar function already in existence. 1984 - Create a print_foo_bar function which calls sprint_foo_bar and prints 1985 the result. 1986 - Create a qprint_foo_bar function which calls upon sprint_foo_bar only if 1987 global value quiet is 0. 1988 - Create a dprint_foo_bar function which calls upon sprint_foo_bar only if 1989 global value debug is 1. 1990 1991 Also, code will be generated to define aliases for each function as well. 1992 Each alias will be created by replacing "print_" in the function name with 1993 "p" For example, the alias for print_foo_bar will be pfoo_bar. 1994 1995 Description of argument(s): 1996 func_names A list of functions for which print 1997 wrapper function code is to be generated. 1998 stderr_func_names A list of functions whose generated code 1999 should print to stderr rather than to 2000 stdout. 2001 replace_dict Please see the create_func_def_string 2002 function in wrap_utils.py for details on 2003 this parameter. This parameter will be 2004 passed directly to create_func_def_string. 2005 func_prefix Prefix to be pre-pended to the generated 2006 function name. 2007 """ 2008 2009 buffer = "" 2010 2011 for func_name in func_names: 2012 if func_name in stderr_func_names: 2013 replace_dict['output_stream'] = "stderr" 2014 else: 2015 replace_dict['output_stream'] = "stdout" 2016 2017 s_func_name = "s" + func_name 2018 q_func_name = "q" + func_name 2019 d_func_name = "d" + func_name 2020 2021 # We don't want to try to redefine the "print" function, thus the 2022 # following if statement. 2023 if func_name != "print": 2024 func_def = create_func_def_string(s_func_name, 2025 func_prefix + func_name, 2026 print_func_template, 2027 replace_dict) 2028 buffer += func_def 2029 2030 func_def = create_func_def_string(s_func_name, 2031 func_prefix + "q" + func_name, 2032 qprint_func_template, replace_dict) 2033 buffer += func_def 2034 2035 func_def = create_func_def_string(s_func_name, 2036 func_prefix + "d" + func_name, 2037 dprint_func_template, replace_dict) 2038 buffer += func_def 2039 2040 func_def = create_func_def_string(s_func_name, 2041 func_prefix + "l" + func_name, 2042 lprint_func_template, replace_dict) 2043 buffer += func_def 2044 2045 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var). 2046 alias = re.sub("print_", "p", func_name) 2047 alias = re.sub("print", "p", alias) 2048 prefixes = [func_prefix + "", "s", func_prefix + "q", 2049 func_prefix + "d", func_prefix + "l"] 2050 for prefix in prefixes: 2051 if alias == "p": 2052 continue 2053 func_def = prefix + alias + " = " + prefix + func_name 2054 buffer += func_def + "\n" 2055 2056 return buffer 2057 2058 2059# In the following section of code, we will dynamically create print versions 2060# for each of the sprint functions defined above. So, for example, where we 2061# have an sprint_time() function defined above that returns the time to the 2062# caller in a string, we will create a corresponding print_time() function 2063# that will print that string directly to stdout. 2064 2065# It can be complicated to follow what's being created below. Here is an 2066# example of the print_time() function that will be created: 2067 2068# def print_time(buffer=''): 2069# gp_print(replace_passwords(sprint_time(buffer=buffer)), stream='stdout') 2070 2071# For each print function defined below, there will also be a qprint, a 2072# dprint and an lprint version defined (e.g. qprint_time, dprint_time, 2073# lprint_time). 2074 2075# The q version of each print function will only print if the quiet variable 2076# is 0. 2077# The d version of each print function will only print if the debug variable 2078# is 1. 2079# The l version of each print function will print the contents as log data. 2080# For conventional programs, this means use of the logging module. For robot 2081# programs it means use of the BuiltIn().log() function. 2082 2083# Templates for the various print wrapper functions. 2084print_func_template = \ 2085 [ 2086 " <mod_qualifier>gp_print(<mod_qualifier>replace_passwords(" 2087 + "<call_line>), stream='<output_stream>')" 2088 ] 2089 2090qprint_func_template = \ 2091 [ 2092 " quiet_default = <mod_qualifier>get_var_value(None, 0, \"quiet\")", 2093 " quiet = <mod_qualifier>get_stack_var(\"quiet\", quiet_default)", 2094 " if int(quiet): return" 2095 ] + print_func_template 2096 2097dprint_func_template = \ 2098 [ 2099 " debug_default = <mod_qualifier>get_var_value(None, 0, \"debug\")", 2100 " debug = <mod_qualifier>get_stack_var(\"debug\", debug_default)", 2101 " if not int(debug): return" 2102 ] + print_func_template 2103 2104lprint_func_template = \ 2105 [ 2106 " <mod_qualifier>set_last_seconds_ix(<mod_qualifier>" 2107 + "lprint_last_seconds_ix())", 2108 " <mod_qualifier>gp_log(<mod_qualifier>replace_passwords" 2109 + "(<call_line>))", 2110 " <mod_qualifier>set_last_seconds_ix(<mod_qualifier>" 2111 + "standard_print_last_seconds_ix())" 2112 ] 2113 2114replace_dict = {'output_stream': 'stdout', 'mod_qualifier': ''} 2115 2116gp_debug_print("robot_env: " + str(robot_env) + "\n") 2117 2118# func_names contains a list of all print functions which should be created 2119# from their sprint counterparts. 2120func_names = ['print_time', 'print_timen', 'print_error', 'print_varx', 2121 'print_var', 'print_vars', 'print_dashes', 'indent', 2122 'print_call_stack', 'print_func_name', 'print_executing', 2123 'print_pgm_header', 'print_issuing', 'print_pgm_footer', 2124 'print_error_report', 'print', 'printn'] 2125 2126# stderr_func_names is a list of functions whose output should go to stderr 2127# rather than stdout. 2128stderr_func_names = ['print_error', 'print_error_report'] 2129 2130func_defs = create_print_wrapper_funcs(func_names, stderr_func_names, 2131 replace_dict) 2132gp_debug_print(func_defs) 2133exec(func_defs) 2134