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