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            format_string = "%" + str(indent) + "s%s\n"
1245            buffer = format_string % ("", loc_var_name + ":")
1246            if fmt & show_type():
1247                buffer = buffer.replace("\n", " " + type_str + "\n")
1248            indent += 2
1249        try:
1250            length = len(var_value)
1251        except TypeError:
1252            length = 0
1253        ix = 0
1254        loc_trailing_char = "\n"
1255        if is_dict(var_value):
1256            if type(child_fmt) is list:
1257                child_quote_keys = (child_fmt[0] & quote_keys())
1258            else:
1259                child_quote_keys = (child_fmt & quote_keys())
1260            for key, value in var_value.items():
1261                if key_list is not None:
1262                    key_list_regex = "^" + "|".join(key_list) + "$"
1263                    if not re.match(key_list_regex, key):
1264                        continue
1265                ix += 1
1266                if ix == length:
1267                    loc_trailing_char = trailing_char
1268                if child_quote_keys:
1269                    key = "'" + key + "'"
1270                key = "[" + str(key) + "]"
1271                buffer += sprint_varx(var_name + key, value, child_fmt, indent,
1272                                      col1_width, loc_trailing_char, key_list,
1273                                      delim)
1274        elif type(var_value) in (list, tuple, set):
1275            for key, value in enumerate(var_value):
1276                ix += 1
1277                if ix == length:
1278                    loc_trailing_char = trailing_char
1279                key = "[" + str(key) + "]"
1280                buffer += sprint_varx(var_name + key, value, child_fmt, indent,
1281                                      col1_width, loc_trailing_char, key_list,
1282                                      delim)
1283        elif isinstance(var_value, argparse.Namespace):
1284            for key in var_value.__dict__:
1285                ix += 1
1286                if ix == length:
1287                    loc_trailing_char = trailing_char
1288                cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \
1289                          + ", var_value." + key + ", child_fmt, indent," \
1290                          + " col1_width, loc_trailing_char, key_list," \
1291                          + " delim)"
1292                exec(cmd_buf)
1293        else:
1294            var_type = type(var_value).__name__
1295            func_name = sys._getframe().f_code.co_name
1296            var_value = "<" + var_type + " type not supported by " + \
1297                        func_name + "()>"
1298            value_format = "%s"
1299            indent -= 2
1300            # Adjust col1_width.
1301            col1_width = col1_width - indent
1302            format_string = "%" + str(indent) + "s%-" \
1303                + str(col1_width) + "s" + value_format + trailing_char
1304            return format_string % ("", str(var_name) + ":", var_value)
1305
1306        return buffer
1307
1308    return ""
1309
1310
1311def sprint_var(*args, **kwargs):
1312    r"""
1313    Figure out the name of the first argument for the caller and then call
1314    sprint_varx with it.  Therefore, the following 2 calls are equivalent:
1315    sprint_varx("var1", var1)
1316    sprint_var(var1)
1317
1318    See sprint_varx for description of arguments.
1319    """
1320
1321    stack_frame = 2
1322    caller_func_name = sprint_func_name(2)
1323    if caller_func_name.endswith("print_var"):
1324        stack_frame += 1
1325    # Get the name of the first variable passed to this function.
1326    var_name = get_arg_name(None, 1, stack_frame)
1327    return sprint_varx(var_name, *args, **kwargs)
1328
1329
1330def sprint_vars(*args, **kwargs):
1331    r"""
1332    Sprint the values of one or more variables.
1333
1334    Description of argument(s):
1335    args                            The variable values which are to be
1336                                    printed.
1337    kwargs                          See sprint_varx (above) for description of
1338                                    additional arguments.
1339    """
1340
1341    stack_frame = 2
1342    caller_func_name = sprint_func_name(2)
1343    if caller_func_name.endswith("print_vars"):
1344        stack_frame += 1
1345
1346    buffer = ""
1347    arg_num = 1
1348    for var_value in args:
1349        var_name = get_arg_name(None, arg_num, stack_frame)
1350        buffer += sprint_varx(var_name, var_value, **kwargs)
1351        arg_num += 1
1352
1353    return buffer
1354
1355
1356def sprint_dashes(indent=dft_indent,
1357                  width=80,
1358                  line_feed=1,
1359                  char="-"):
1360    r"""
1361    Return a string of dashes to the caller.
1362
1363    Description of argument(s):
1364    indent                          The number of characters to indent the
1365                                    output.
1366    width                           The width of the string of dashes.
1367    line_feed                       Indicates whether the output should end
1368                                    with a line feed.
1369    char                            The character to be repeated in the output
1370                                    string.
1371    """
1372
1373    width = int(width)
1374    buffer = " " * int(indent) + char * width
1375    if line_feed:
1376        buffer += "\n"
1377
1378    return buffer
1379
1380
1381def sindent(text="",
1382            indent=0):
1383    r"""
1384    Pre-pend the specified number of characters to the text string (i.e.
1385    indent it) and return it.
1386
1387    Description of argument(s):
1388    text                            The string to be indented.
1389    indent                          The number of characters to indent the
1390                                    string.
1391    """
1392
1393    format_string = "%" + str(indent) + "s%s"
1394    buffer = format_string % ("", text)
1395
1396    return buffer
1397
1398
1399func_line_style_std = None
1400func_line_style_short = 1
1401
1402
1403def sprint_func_line(stack_frame, style=None):
1404    r"""
1405    For the given stack_frame, return a formatted string containing the
1406    function name and all its arguments.
1407
1408    Example:
1409
1410    func1(last_name = 'walsh', first_name = 'mikey')
1411
1412    Description of argument(s):
1413    stack_frame                     A stack frame (such as is returned by
1414                                    inspect.stack()).
1415    style                           Indicates the style or formatting of the
1416                                    result string.  Acceptable values are
1417                                    shown above.
1418
1419    Description of styles:
1420    func_line_style_std             The standard formatting.
1421    func_line_style_short           1) The self parm (associated with methods)
1422                                    will be dropped. 2) The args and kwargs
1423                                    values will be treated as special.  In
1424                                    both cases the arg name ('args' or
1425                                    'kwargs') will be dropped and only the
1426                                    values will be shown.
1427    """
1428
1429    func_name = str(stack_frame[3])
1430    if func_name == "?":
1431        # "?" is the name used when code is not in a function.
1432        func_name = "(none)"
1433
1434    if func_name == "<module>":
1435        # If the func_name is the "main" program, we simply get the command
1436        # line call string.
1437        func_and_args = ' '.join(sys.argv)
1438    else:
1439        # Get the program arguments.
1440        (args, varargs, keywords, locals) =\
1441            inspect.getargvalues(stack_frame[0])
1442
1443        args_list = []
1444        for arg_name in filter(None, args + [varargs, keywords]):
1445            # Get the arg value from frame locals.
1446            arg_value = locals[arg_name]
1447            if arg_name == 'self':
1448                if style == func_line_style_short:
1449                    continue
1450                # Manipulations to improve output for class methods.
1451                func_name = arg_value.__class__.__name__ + "." + func_name
1452                args_list.append(arg_name + " = <self>")
1453            elif (style == func_line_style_short
1454                  and arg_name == 'args'
1455                  and type(arg_value) in (list, tuple)):
1456                if len(arg_value) == 0:
1457                    continue
1458                args_list.append(repr(', '.join(arg_value)))
1459            elif (style == func_line_style_short
1460                  and arg_name == 'kwargs'
1461                  and type(arg_value) is dict):
1462                for key, value in arg_value.items():
1463                    args_list.append(key + "=" + repr(value))
1464            else:
1465                args_list.append(arg_name + " = " + repr(arg_value))
1466        args_str = "(" + ', '.join(map(str, args_list)) + ")"
1467
1468        # Now we need to print this in a nicely-wrapped way.
1469        func_and_args = func_name + args_str
1470
1471    return func_and_args
1472
1473
1474def sprint_call_stack(indent=0,
1475                      stack_frame_ix=0,
1476                      style=None):
1477    r"""
1478    Return a call stack report for the given point in the program with line
1479    numbers, function names and function parameters and arguments.
1480
1481    Sample output:
1482
1483    -------------------------------------------------------------------------
1484    Python function call stack
1485
1486    Line # Function name and arguments
1487    ------ ------------------------------------------------------------------
1488       424 sprint_call_stack()
1489         4 print_call_stack()
1490        31 func1(last_name = 'walsh', first_name = 'mikey')
1491        59 /tmp/scr5.py
1492    -------------------------------------------------------------------------
1493
1494    Description of argument(s):
1495    indent                          The number of characters to indent each
1496                                    line of output.
1497    stack_frame_ix                  The index of the first stack frame which
1498                                    is to be returned.
1499    style                           See the sprint_line_func prolog above for
1500                                    details.
1501    """
1502
1503    buffer = ""
1504    buffer += sprint_dashes(indent)
1505    buffer += sindent("Python function call stack\n\n", indent)
1506    buffer += sindent("Line # Function name and arguments\n", indent)
1507    buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73)
1508
1509    # Grab the current program stack.
1510    work_around_inspect_stack_cwd_failure()
1511    current_stack = inspect.stack()
1512
1513    # Process each frame in turn.
1514    format_string = "%6s %s\n"
1515    ix = 0
1516    for stack_frame in current_stack:
1517        if ix < stack_frame_ix:
1518            ix += 1
1519            continue
1520        # Make the line number shown to be the line where one finds the line
1521        # shown.
1522        try:
1523            line_num = str(current_stack[ix + 1][2])
1524        except IndexError:
1525            line_num = ""
1526        func_and_args = sprint_func_line(stack_frame, style=style)
1527
1528        buffer += sindent(format_string % (line_num, func_and_args), indent)
1529        ix += 1
1530
1531    buffer += sprint_dashes(indent)
1532
1533    return buffer
1534
1535
1536def sprint_executing(stack_frame_ix=None, style=None):
1537    r"""
1538    Print a line indicating what function is executing and with what parameter
1539    values.  This is useful for debugging.
1540
1541    Sample output:
1542
1543    #(CDT) 2016/08/25 17:54:27 - Executing: func1(x = 1)
1544
1545    Description of argument(s):
1546    stack_frame_ix                  The index of the stack frame whose
1547                                    function info should be returned.  If the
1548                                    caller does not specify a value, this
1549                                    function will set the value to 1 which is
1550                                    the index of the caller's stack frame.  If
1551                                    the caller is the wrapper function
1552                                    "print_executing", this function will bump
1553                                    it up by 1.
1554    style                           See the sprint_line_func prolog above for
1555                                    details.
1556    """
1557
1558    # If user wants default stack_frame_ix.
1559    if stack_frame_ix is None:
1560        func_name = sys._getframe().f_code.co_name
1561        caller_func_name = sys._getframe(1).f_code.co_name
1562        if caller_func_name.endswith(func_name[1:]):
1563            stack_frame_ix = 2
1564        else:
1565            stack_frame_ix = 1
1566
1567    work_around_inspect_stack_cwd_failure()
1568    stack_frame = inspect.stack()[stack_frame_ix]
1569
1570    func_and_args = sprint_func_line(stack_frame, style)
1571
1572    return sprint_time() + "Executing: " + func_and_args + "\n"
1573
1574
1575def sprint_pgm_header(indent=0,
1576                      linefeed=1):
1577    r"""
1578    Return a standardized header that programs should print at the beginning
1579    of the run.  It includes useful information like command line, pid,
1580    userid, program parameters, etc.
1581
1582    Description of argument(s):
1583    indent                          The number of characters to indent each
1584                                    line of output.
1585    linefeed                        Indicates whether a line feed be included
1586                                    at the beginning and end of the report.
1587    """
1588
1589    col1_width = dft_col1_width + indent
1590
1591    buffer = ""
1592    if linefeed:
1593        buffer = "\n"
1594
1595    if robot_env:
1596        suite_name = BuiltIn().get_variable_value("${suite_name}")
1597        buffer += sindent(sprint_time("Running test suite \"" + suite_name
1598                                      + "\".\n"), indent)
1599
1600    buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent)
1601    buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n",
1602                      indent)
1603    buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent,
1604                          col1_width)
1605    # We want the output to show a customized name for the pid and pgid but
1606    # we want it to look like a valid variable name.  Therefore, we'll use
1607    # pgm_name_var_name which was set when this module was imported.
1608    buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent,
1609                          col1_width)
1610    buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent,
1611                          col1_width)
1612    userid_num = str(os.geteuid())
1613    try:
1614        username = os.getlogin()
1615    except OSError:
1616        if userid_num == "0":
1617            username = "root"
1618        else:
1619            username = "?"
1620    buffer += sprint_varx("uid", userid_num + " (" + username
1621                          + ")", 0, indent, col1_width)
1622    buffer += sprint_varx("gid", str(os.getgid()) + " ("
1623                          + str(grp.getgrgid(os.getgid()).gr_name) + ")", 0,
1624                          indent, col1_width)
1625    buffer += sprint_varx("host_name", socket.gethostname(), 0, indent,
1626                          col1_width)
1627    try:
1628        DISPLAY = os.environ['DISPLAY']
1629    except KeyError:
1630        DISPLAY = ""
1631    buffer += sprint_var(DISPLAY, 0, indent, col1_width)
1632    PYTHON_VERSION = os.environ.get('PYTHON_VERSION', None)
1633    if PYTHON_VERSION is not None:
1634        buffer += sprint_var(PYTHON_VERSION, 0, indent, col1_width)
1635    PYTHON_PGM_PATH = os.environ.get('PYTHON_PGM_PATH', None)
1636    if PYTHON_PGM_PATH is not None:
1637        buffer += sprint_var(PYTHON_PGM_PATH, 0, indent, col1_width)
1638    python_version = sys.version.replace("\n", "")
1639    buffer += sprint_var(python_version, 0, indent, col1_width)
1640    ROBOT_VERSION = os.environ.get('ROBOT_VERSION', None)
1641    if ROBOT_VERSION is not None:
1642        buffer += sprint_var(ROBOT_VERSION, 0, indent, col1_width)
1643    ROBOT_PGM_PATH = os.environ.get('ROBOT_PGM_PATH', None)
1644    if ROBOT_PGM_PATH is not None:
1645        buffer += sprint_var(ROBOT_PGM_PATH, 0, indent, col1_width)
1646
1647    # TODO: Add code to print caller's parms.
1648
1649    # __builtin__.arg_obj is created by the get_arg module function,
1650    # gen_get_options.
1651    try:
1652        buffer += ga.sprint_args(__builtin__.arg_obj, indent)
1653    except AttributeError:
1654        pass
1655
1656    if robot_env:
1657        # Get value of global parm_list.
1658        parm_list = BuiltIn().get_variable_value("${parm_list}")
1659
1660        for parm in parm_list:
1661            parm_value = BuiltIn().get_variable_value("${" + parm + "}")
1662            buffer += sprint_varx(parm, parm_value, 0, indent, col1_width)
1663
1664        # Setting global program_pid.
1665        BuiltIn().set_global_variable("${program_pid}", os.getpid())
1666
1667    if linefeed:
1668        buffer += "\n"
1669
1670    return buffer
1671
1672
1673def sprint_error_report(error_text="\n",
1674                        indent=2,
1675                        format=None,
1676                        stack_frame_ix=None):
1677    r"""
1678    Return a string with a standardized report which includes the caller's
1679    error text, the call stack and the program header.
1680
1681    Description of argument(s):
1682    error_text                      The error text to be included in the
1683                                    report.  The caller should include any
1684                                    needed linefeeds.
1685    indent                          The number of characters to indent each
1686                                    line of output.
1687    format                          Long or short format.  Long includes
1688                                    extras like lines of dashes, call stack,
1689                                    etc.
1690    stack_frame_ix                  The index of the first stack frame which
1691                                    is to be shown in the print_call_stack
1692                                    portion of the error report.
1693    """
1694
1695    # Process input.
1696    indent = int(indent)
1697    if format is None:
1698        if robot_env:
1699            format = 'short'
1700        else:
1701            format = 'long'
1702    error_text = error_text.rstrip('\n') + '\n'
1703
1704    if format == 'short':
1705        return sprint_error(error_text)
1706
1707    buffer = ""
1708    buffer += sprint_dashes(width=120, char="=")
1709    buffer += sprint_error(error_text)
1710    buffer += "\n"
1711    if not stack_frame_ix:
1712        # Calling sprint_call_stack with stack_frame_ix of 0 causes it to
1713        # show itself and this function in the call stack.  This is not
1714        # helpful to a debugger and is therefore clutter.  We will adjust the
1715        # stack_frame_ix to hide that information.
1716        stack_frame_ix = 1
1717        caller_func_name = sprint_func_name(1)
1718        if caller_func_name.endswith("print_error_report"):
1719            stack_frame_ix += 1
1720        caller_func_name = sprint_func_name(2)
1721        if caller_func_name.endswith("print_error_report"):
1722            stack_frame_ix += 1
1723    buffer += sprint_call_stack(indent, stack_frame_ix)
1724    buffer += sprint_pgm_header(indent)
1725    buffer += sprint_dashes(width=120, char="=")
1726
1727    return buffer
1728
1729
1730def sprint_issuing(cmd_buf,
1731                   test_mode=0):
1732    r"""
1733    Return a line indicating a command that the program is about to execute.
1734
1735    Sample output for a cmd_buf of "ls"
1736
1737    #(CDT) 2016/08/25 17:57:36 - Issuing: ls
1738
1739    Description of argument(s):
1740    cmd_buf                         The command to be executed by caller.
1741    test_mode                       With test_mode set, the output will look
1742                                    like this:
1743
1744    #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls
1745
1746    """
1747
1748    buffer = sprint_time()
1749    if test_mode:
1750        buffer += "(test_mode) "
1751    if type(cmd_buf) is list:
1752        # Assume this is a robot command in the form of a list.
1753        cmd_buf = '  '.join([str(element) for element in cmd_buf])
1754    buffer += "Issuing: " + cmd_buf + "\n"
1755
1756    return buffer
1757
1758
1759def sprint_pgm_footer():
1760    r"""
1761    Return a standardized footer that programs should print at the end of the
1762    program run.  It includes useful information like total run time, etc.
1763    """
1764
1765    buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n"
1766
1767    total_time = time.time() - start_time
1768    total_time_string = "%0.6f" % total_time
1769
1770    buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string)
1771    buffer += "\n"
1772
1773    return buffer
1774
1775
1776def sprint(buffer=""):
1777    r"""
1778    Simply return the user's buffer.  This function is used by the qprint and
1779    dprint functions defined dynamically below, i.e. it would not normally be
1780    called for general use.
1781
1782    Description of argument(s).
1783    buffer                          This will be returned to the caller.
1784    """
1785
1786    try:
1787        return str(buffer)
1788    except UnicodeEncodeError:
1789        return buffer
1790
1791
1792def sprintn(buffer=""):
1793    r"""
1794    Simply return the user's buffer with a line feed.  This function is used
1795    by the qprint and dprint functions defined dynamically below, i.e. it
1796    would not normally be called for general use.
1797
1798    Description of argument(s).
1799    buffer                          This will be returned to the caller.
1800    """
1801
1802    try:
1803        buffer = str(buffer) + "\n"
1804    except UnicodeEncodeError:
1805        buffer = buffer + "\n"
1806
1807    return buffer
1808
1809
1810def gp_print(buffer,
1811             stream='stdout'):
1812    r"""
1813    Print the buffer using either sys.stdout.write or BuiltIn().log_to_console
1814    depending on whether we are running in a robot environment.
1815
1816    This function is intended for use only by other functions in this module.
1817
1818    Description of argument(s):
1819    buffer                          The string to be printed.
1820    stream                          Either "stdout" or "stderr".
1821    """
1822
1823    if robot_env:
1824        BuiltIn().log_to_console(buffer, stream=stream, no_newline=True)
1825    else:
1826        if stream == "stdout":
1827            sys.stdout.write(buffer)
1828            sys.stdout.flush()
1829        else:
1830            sys.stderr.write(buffer)
1831            sys.stderr.flush()
1832
1833
1834def gp_log(buffer):
1835    r"""
1836    Log the buffer using either python logging or BuiltIn().log depending on
1837    whether we are running in a robot environment.
1838
1839    This function is intended for use only by other functions in this module.
1840
1841    Description of argument(s):
1842    buffer                          The string to be logged.
1843    """
1844
1845    if robot_env:
1846        BuiltIn().log(buffer)
1847    else:
1848        logging.warning(buffer)
1849
1850
1851def gp_debug_print(buffer):
1852    r"""
1853    Print with gp_print only if gen_print_debug is set.
1854
1855    This function is intended for use only by other functions in this module.
1856
1857    Description of argument(s):
1858    buffer                          The string to be printed.
1859    """
1860
1861    if not gen_print_debug:
1862        return
1863
1864    gp_print(buffer)
1865
1866
1867def get_var_value(var_value=None,
1868                  default=1,
1869                  var_name=None):
1870    r"""
1871    Return either var_value, the corresponding global value or default.
1872
1873    If var_value is not None, it will simply be returned.
1874
1875    If var_value is None, this function will return the corresponding global
1876    value of the variable in question.
1877
1878    Note: For global values, if we are in a robot environment,
1879    get_variable_value will be used.  Otherwise, the __builtin__ version of
1880    the variable is returned (which are set by gen_arg.py functions).
1881
1882    If there is no global value associated with the variable, default is
1883    returned.
1884
1885    This function is useful for other functions in setting default values for
1886    parameters.
1887
1888    Example use:
1889
1890    def my_func(quiet=None):
1891
1892      quiet = int(get_var_value(quiet, 0))
1893
1894    Example calls to my_func():
1895
1896    In the following example, the caller is explicitly asking to have quiet be
1897    set to 1.
1898
1899    my_func(quiet=1)
1900
1901    In the following example, quiet will be set to the global value of quiet,
1902    if defined, or to 0 (the default).
1903
1904    my_func()
1905
1906    Description of argument(s):
1907    var_value                       The value to be returned (if not equal to
1908                                    None).
1909    default                         The value that is returned if var_value is
1910                                    None and there is no corresponding global
1911                                    value defined.
1912    var_name                        The name of the variable whose value is to
1913                                    be returned.  Under most circumstances,
1914                                    this value need not be provided.  This
1915                                    function can figure out the name of the
1916                                    variable passed as var_value.  One
1917                                    exception to this would be if this
1918                                    function is called directly from a .robot
1919                                    file.
1920    """
1921
1922    if var_value is not None:
1923        return var_value
1924
1925    if var_name is None:
1926        var_name = get_arg_name(None, 1, 2)
1927
1928    if robot_env:
1929        var_value = BuiltIn().get_variable_value("${" + var_name + "}",
1930                                                 default)
1931    else:
1932        var_value = getattr(__builtin__, var_name, default)
1933
1934    return var_value
1935
1936
1937def get_stack_var(var_name,
1938                  default="",
1939                  init_stack_ix=2):
1940    r"""
1941    Starting with the caller's stack level, search upward in the call stack
1942    for a variable named var_name and return its value.  If the variable
1943    cannot be found in the stack, attempt to get the global value.  If the
1944    variable still cannot be found, return default.
1945
1946    Example code:
1947
1948    def func12():
1949        my_loc_var1 = get_stack_var('my_var1', "default value")
1950
1951    def func11():
1952        my_var1 = 11
1953        func12()
1954
1955    In this example, get_stack_var will find the value of my_var1 in func11's
1956    stack and will therefore return the value 11.  Therefore, my_loc_var1
1957    would get set to 11.
1958
1959    Description of argument(s):
1960    var_name                        The name of the variable to be searched
1961                                    for.
1962    default                         The value to return if the the variable
1963                                    cannot be found.
1964    init_stack_ix                   The initial stack index from which to
1965                                    begin the search.  0 would be the index of
1966                                    this func1tion ("get_stack_var"), 1 would
1967                                    be the index of the function calling this
1968                                    function, etc.
1969    """
1970
1971    work_around_inspect_stack_cwd_failure()
1972    default = get_var_value(var_name=var_name, default=default)
1973    return next((frame[0].f_locals[var_name]
1974                 for frame in inspect.stack()[init_stack_ix:]
1975                 if var_name in frame[0].f_locals), default)
1976
1977
1978# hidden_text is a list of passwords which are to be replaced with asterisks
1979# by print functions defined in this module.
1980hidden_text = []
1981# password_regex is created based on the contents of hidden_text.
1982password_regex = ""
1983
1984
1985def register_passwords(*args):
1986    r"""
1987    Register one or more passwords which are to be hidden in output produced
1988    by the print functions in this module.
1989
1990    Note:  Blank password values are NOT registered.  They are simply ignored.
1991
1992    Description of argument(s):
1993    args                            One or more password values.  If a given
1994                                    password value is already registered, this
1995                                    function will simply do nothing.
1996    """
1997
1998    global hidden_text
1999    global password_regex
2000
2001    for password in args:
2002        if password == "":
2003            break
2004        if password in hidden_text:
2005            break
2006
2007        # Place the password into the hidden_text list.
2008        hidden_text.append(password)
2009        # Create a corresponding password regular expression.  Escape regex
2010        # special characters too.
2011        password_regex = '(' +\
2012            '|'.join([re.escape(x) for x in hidden_text]) + ')'
2013
2014
2015def replace_passwords(buffer):
2016    r"""
2017    Return the buffer but with all registered passwords replaced by a string
2018    of asterisks.
2019
2020
2021    Description of argument(s):
2022    buffer                          The string to be returned but with
2023                                    passwords replaced.
2024    """
2025
2026    global password_regex
2027
2028    if int(os.environ.get("DEBUG_SHOW_PASSWORDS", "0")):
2029        return buffer
2030
2031    if password_regex == "":
2032        # No passwords to replace.
2033        return buffer
2034
2035    return re.sub(password_regex, "********", buffer)
2036
2037
2038def create_print_wrapper_funcs(func_names,
2039                               stderr_func_names,
2040                               replace_dict,
2041                               func_prefix=""):
2042    r"""
2043    Generate code for print wrapper functions and return the generated code as
2044    a string.
2045
2046    To illustrate, suppose there is a "print_foo_bar" function in the
2047    func_names list.
2048    This function will...
2049    - Expect that there is an sprint_foo_bar function already in existence.
2050    - Create a print_foo_bar function which calls sprint_foo_bar and prints
2051      the result.
2052    - Create a qprint_foo_bar function which calls upon sprint_foo_bar only if
2053      global value quiet is 0.
2054    - Create a dprint_foo_bar function which calls upon sprint_foo_bar only if
2055      global value debug is 1.
2056
2057    Also, code will be generated to define aliases for each function as well.
2058    Each alias will be created by replacing "print_" in the function name with
2059    "p"  For example, the alias for print_foo_bar will be pfoo_bar.
2060
2061    Description of argument(s):
2062    func_names                      A list of functions for which print
2063                                    wrapper function code is to be generated.
2064    stderr_func_names               A list of functions whose generated code
2065                                    should print to stderr rather than to
2066                                    stdout.
2067    replace_dict                    Please see the create_func_def_string
2068                                    function in wrap_utils.py for details on
2069                                    this parameter.  This parameter will be
2070                                    passed directly to create_func_def_string.
2071    func_prefix                     Prefix to be pre-pended to the generated
2072                                    function name.
2073    """
2074
2075    buffer = ""
2076
2077    for func_name in func_names:
2078        if func_name in stderr_func_names:
2079            replace_dict['output_stream'] = "stderr"
2080        else:
2081            replace_dict['output_stream'] = "stdout"
2082
2083        s_func_name = "s" + func_name
2084        q_func_name = "q" + func_name
2085        d_func_name = "d" + func_name
2086
2087        # We don't want to try to redefine the "print" function, thus the
2088        # following if statement.
2089        if func_name != "print":
2090            func_def = create_func_def_string(s_func_name,
2091                                              func_prefix + func_name,
2092                                              print_func_template,
2093                                              replace_dict)
2094            buffer += func_def
2095
2096        func_def = create_func_def_string(s_func_name,
2097                                          func_prefix + "q" + func_name,
2098                                          qprint_func_template, replace_dict)
2099        buffer += func_def
2100
2101        func_def = create_func_def_string(s_func_name,
2102                                          func_prefix + "d" + func_name,
2103                                          dprint_func_template, replace_dict)
2104        buffer += func_def
2105
2106        func_def = create_func_def_string(s_func_name,
2107                                          func_prefix + "l" + func_name,
2108                                          lprint_func_template, replace_dict)
2109        buffer += func_def
2110
2111        # Create abbreviated aliases (e.g. spvar is an alias for sprint_var).
2112        alias = re.sub("print_", "p", func_name)
2113        alias = re.sub("print", "p", alias)
2114        prefixes = [func_prefix + "", "s", func_prefix + "q",
2115                    func_prefix + "d", func_prefix + "l"]
2116        for prefix in prefixes:
2117            if alias == "p":
2118                continue
2119            func_def = prefix + alias + " = " + prefix + func_name
2120            buffer += func_def + "\n"
2121
2122    return buffer
2123
2124
2125# In the following section of code, we will dynamically create print versions
2126# for each of the sprint functions defined above.  So, for example, where we
2127# have an sprint_time() function defined above that returns the time to the
2128# caller in a string, we will create a corresponding print_time() function
2129# that will print that string directly to stdout.
2130
2131# It can be complicated to follow what's being created below.  Here is an
2132# example of the print_time() function that will be created:
2133
2134# def print_time(buffer=''):
2135#     gp_print(replace_passwords(sprint_time(buffer=buffer)), stream='stdout')
2136
2137# For each print function defined below, there will also be a qprint, a
2138# dprint and an lprint version defined (e.g. qprint_time, dprint_time,
2139# lprint_time).
2140
2141# The q version of each print function will only print if the quiet variable
2142# is 0.
2143# The d version of each print function will only print if the debug variable
2144# is 1.
2145# The l version of each print function will print the contents as log data.
2146# For conventional programs, this means use of the logging module.  For robot
2147# programs it means use of the BuiltIn().log() function.
2148
2149# Templates for the various print wrapper functions.
2150print_func_template = \
2151    [
2152        "    <mod_qualifier>gp_print(<mod_qualifier>replace_passwords("
2153        + "<call_line>), stream='<output_stream>')"
2154    ]
2155
2156qprint_func_template = \
2157    [
2158        "    quiet = <mod_qualifier>get_stack_var(\"quiet\", 0)",
2159        "    if int(quiet): return"
2160    ] + print_func_template
2161
2162dprint_func_template = \
2163    [
2164        "    debug = <mod_qualifier>get_stack_var(\"debug\", 0)",
2165        "    if not int(debug): return"
2166    ] + print_func_template
2167
2168lprint_func_template = \
2169    [
2170        "    <mod_qualifier>set_last_seconds_ix(<mod_qualifier>"
2171        + "lprint_last_seconds_ix())",
2172        "    <mod_qualifier>gp_log(<mod_qualifier>replace_passwords"
2173        + "(<call_line>))",
2174        "    <mod_qualifier>set_last_seconds_ix(<mod_qualifier>"
2175        + "standard_print_last_seconds_ix())"
2176    ]
2177
2178replace_dict = {'output_stream': 'stdout', 'mod_qualifier': ''}
2179
2180gp_debug_print("robot_env: " + str(robot_env) + "\n")
2181
2182# func_names contains a list of all print functions which should be created
2183# from their sprint counterparts.
2184func_names = ['print_time', 'print_timen', 'print_error', 'print_varx',
2185              'print_var', 'print_vars', 'print_dashes', 'indent',
2186              'print_call_stack', 'print_func_name', 'print_executing',
2187              'print_pgm_header', 'print_issuing', 'print_pgm_footer',
2188              'print_error_report', 'print', 'printn']
2189
2190# stderr_func_names is a list of functions whose output should go to stderr
2191# rather than stdout.
2192stderr_func_names = ['print_error', 'print_error_report']
2193
2194func_defs = create_print_wrapper_funcs(func_names, stderr_func_names,
2195                                       replace_dict)
2196gp_debug_print(func_defs)
2197exec(func_defs)
2198