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