blob: 18aa8960ab45591e9d7f953b8c6a8127fb55731d [file] [log] [blame]
Michael Walshde791732016-09-06 14:25:24 -05001#!/usr/bin/env python
2
3r"""
4This module provides many valuable print functions such as sprint_var,
5sprint_time, sprint_error, sprint_call_stack.
6"""
7
8import sys
9import os
10import time
11import inspect
12import re
13import grp
14import socket
15import argparse
Michael Walsh7423c012016-10-04 10:27:21 -050016import __builtin__
17import logging
Michael Walshbec416d2016-11-10 08:54:52 -060018import collections
Michael Walshfd2733c2017-11-13 11:36:20 -060019from wrap_utils import *
Michael Walshbec416d2016-11-10 08:54:52 -060020
Michael Walshbec416d2016-11-10 08:54:52 -060021try:
Michael Walsh2ee77cd2017-03-08 11:50:17 -060022 robot_env = 1
Michael Walshbec416d2016-11-10 08:54:52 -060023 from robot.utils import DotDict
Michael Walsh8e6deb42017-01-27 14:22:41 -060024 from robot.utils import NormalizedDict
Michael Walsh2ee77cd2017-03-08 11:50:17 -060025 from robot.libraries.BuiltIn import BuiltIn
Michael Walshb1500152017-04-12 15:42:43 -050026 # Having access to the robot libraries alone does not indicate that we
27 # are in a robot environment. The following try block should confirm that.
28 try:
29 var_value = BuiltIn().get_variable_value("${SUITE_NAME}", "")
30 except:
31 robot_env = 0
Michael Walshbec416d2016-11-10 08:54:52 -060032except ImportError:
Michael Walsh2ee77cd2017-03-08 11:50:17 -060033 robot_env = 0
Michael Walsh7423c012016-10-04 10:27:21 -050034
35import gen_arg as ga
Michael Walshde791732016-09-06 14:25:24 -050036
37# Setting these variables for use both inside this module and by programs
38# importing this module.
Michael Walshbf605652017-09-01 12:33:26 -050039pgm_file_path = sys.argv[0]
40pgm_name = os.path.basename(pgm_file_path)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -050041pgm_dir_path = os.path.normpath(re.sub("/" + pgm_name, "", pgm_file_path)) +\
42 os.path.sep
Michael Walsh7423c012016-10-04 10:27:21 -050043
Michael Walshde791732016-09-06 14:25:24 -050044
45# Some functions (e.g. sprint_pgm_header) have need of a program name value
46# that looks more like a valid variable name. Therefore, we'll swap odd
47# characters like "." out for underscores.
48pgm_name_var_name = pgm_name.replace(".", "_")
49
50# Initialize global values used as defaults by print_time, print_var, etc.
51col1_indent = 0
52
53# Calculate default column width for print_var functions based on environment
54# variable settings. The objective is to make the variable values line up
55# nicely with the time stamps.
56col1_width = 29
Michael Walshb1500152017-04-12 15:42:43 -050057
58NANOSECONDS = os.environ.get('NANOSECONDS', '1')
59
Michael Walshde791732016-09-06 14:25:24 -050060
61if NANOSECONDS == "1":
62 col1_width = col1_width + 7
63
Michael Walshb1500152017-04-12 15:42:43 -050064SHOW_ELAPSED_TIME = os.environ.get('SHOW_ELAPSED_TIME', '1')
Michael Walshde791732016-09-06 14:25:24 -050065
66if SHOW_ELAPSED_TIME == "1":
67 if NANOSECONDS == "1":
68 col1_width = col1_width + 14
69 else:
70 col1_width = col1_width + 7
71
72# Initialize some time variables used in module functions.
73start_time = time.time()
74sprint_time_last_seconds = start_time
75
Michael Walsh2ee77cd2017-03-08 11:50:17 -060076# The user can set environment variable "GEN_PRINT_DEBUG" to get debug output
77# from this module.
78gen_print_debug = int(os.environ.get('GEN_PRINT_DEBUG', 0))
Michael Walsh7423c012016-10-04 10:27:21 -050079
Michael Walshde791732016-09-06 14:25:24 -050080
Michael Walshde791732016-09-06 14:25:24 -050081def sprint_func_name(stack_frame_ix=None):
Michael Walshde791732016-09-06 14:25:24 -050082 r"""
83 Return the function name associated with the indicated stack frame.
84
85 Description of arguments:
86 stack_frame_ix The index of the stack frame whose
87 function name should be returned. If the
Michael Walsh2ee77cd2017-03-08 11:50:17 -060088 caller does not specify a value, this
Michael Walshde791732016-09-06 14:25:24 -050089 function will set the value to 1 which is
90 the index of the caller's stack frame. If
91 the caller is the wrapper function
92 "print_func_name", this function will bump
93 it up by 1.
94 """
95
96 # If user specified no stack_frame_ix, we'll set it to a proper default
97 # value.
98 if stack_frame_ix is None:
99 func_name = sys._getframe().f_code.co_name
100 caller_func_name = sys._getframe(1).f_code.co_name
101 if func_name[1:] == caller_func_name:
102 stack_frame_ix = 2
103 else:
104 stack_frame_ix = 1
105
106 func_name = sys._getframe(stack_frame_ix).f_code.co_name
107
108 return func_name
109
Michael Walshde791732016-09-06 14:25:24 -0500110
Michael Walsh1173a522018-05-21 17:24:51 -0500111def get_line_indent(line):
112 r"""
113 Return the number of spaces at the beginning of the line.
114 """
115
116 return len(line) - len(line.lstrip(' '))
117
118
Michael Walshde791732016-09-06 14:25:24 -0500119# get_arg_name is not a print function per se. I have included it in this
120# module because it is used by sprint_var which is found in this module.
Michael Walshde791732016-09-06 14:25:24 -0500121def get_arg_name(var,
122 arg_num=1,
123 stack_frame_ix=1):
Michael Walshde791732016-09-06 14:25:24 -0500124 r"""
125 Return the "name" of an argument passed to a function. This could be a
126 literal or a variable name.
127
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600128 Description of arguments:
Michael Walshde791732016-09-06 14:25:24 -0500129 var The variable whose name you want returned.
Michael Walsh1173a522018-05-21 17:24:51 -0500130 arg_num The arg number whose name is to be
131 returned. To illustrate how arg_num is
132 processed, suppose that a programmer codes
133 this line: "rc, outbuf = my_func(var1,
134 var2)" and suppose that my_func has this
135 line of code: "result = gp.get_arg_name(0,
136 arg_num, 2)". If arg_num is positive, the
137 indicated argument is returned. For
138 example, if arg_num is 1, "var1" would be
139 returned, If arg_num is 2, "var2" would be
140 returned. If arg_num exceeds the number
141 of arguments, get_arg_name will simply
142 return a complete list of the arguments.
143 If arg_num is 0, get_arg_name will return
144 the name of the target function as
145 specified in the calling line ("my_func"
146 in this case). To clarify, if the caller
147 of the target function uses an alias
148 function name, the alias name would be
149 returned. If arg_num is negative, an
150 lvalue variable name is returned.
151 Continuing with the given example, if
152 arg_num is -2 the 2nd parm to the left of
153 the "=" ("rc" in this case) should be
154 returned. If arg_num is -1, the 1st parm
155 to the left of the "=" ("out_buf" in this
156 case) should be returned. If arg_num is
157 less than -2, an entire dictionary is
158 returned. The keys to the dictionary for
159 this example would be -2 and -1.
Michael Walshde791732016-09-06 14:25:24 -0500160 stack_frame_ix The stack frame index of the target
161 function. This value must be 1 or
162 greater. 1 would indicate get_arg_name's
163 stack frame. 2 would be the caller of
164 get_arg_name's stack frame, etc.
165
166 Example 1:
167
168 my_var = "mike"
169 var_name = get_arg_name(my_var)
170
171 In this example, var_name will receive the value "my_var".
172
173 Example 2:
174
175 def test1(var):
176 # Getting the var name of the first arg to this function, test1.
177 # Note, in this case, it doesn't matter what you pass as the first arg
178 # to get_arg_name since it is the caller's variable name that matters.
179 dummy = 1
180 arg_num = 1
181 stack_frame = 2
182 var_name = get_arg_name(dummy, arg_num, stack_frame)
183
184 # Mainline...
185
186 another_var = "whatever"
187 test1(another_var)
188
189 In this example, var_name will be set to "another_var".
190
191 """
192
193 # Note: I wish to avoid recursion so I refrain from calling any function
194 # that calls this function (i.e. sprint_var, valid_value, etc.).
195
Michael Walsh23e7f492017-01-10 11:34:47 -0600196 # The user can set environment variable "GET_ARG_NAME_DEBUG" to get debug
197 # output from this function.
198 local_debug = int(os.environ.get('GET_ARG_NAME_DEBUG', 0))
199 # In addition to GET_ARG_NAME_DEBUG, the user can set environment
200 # variable "GET_ARG_NAME_SHOW_SOURCE" to have this function include source
201 # code in the debug output.
202 local_debug_show_source = int(
203 os.environ.get('GET_ARG_NAME_SHOW_SOURCE', 0))
Michael Walshde791732016-09-06 14:25:24 -0500204
Michael Walshde791732016-09-06 14:25:24 -0500205 if stack_frame_ix < 1:
206 print_error("Programmer error - Variable \"stack_frame_ix\" has an" +
207 " invalid value of \"" + str(stack_frame_ix) + "\". The" +
208 " value must be an integer that is greater than or equal" +
209 " to 1.\n")
210 return
211
212 if local_debug:
213 debug_indent = 2
Michael Walsh23e7f492017-01-10 11:34:47 -0600214 print("")
215 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500216 print(sprint_func_name() + "() parms:")
217 print_varx("var", var, 0, debug_indent)
218 print_varx("arg_num", arg_num, 0, debug_indent)
219 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600220 print("")
221 print_call_stack(debug_indent, 2)
Michael Walshde791732016-09-06 14:25:24 -0500222
Michael Walsh23e7f492017-01-10 11:34:47 -0600223 for count in range(0, 2):
224 try:
225 frame, filename, cur_line_no, function_name, lines, index = \
226 inspect.stack()[stack_frame_ix]
227 except IndexError:
228 print_error("Programmer error - The caller has asked for" +
229 " information about the stack frame at index \"" +
230 str(stack_frame_ix) + "\". However, the stack" +
231 " only contains " + str(len(inspect.stack())) +
232 " entries. Therefore the stack frame index is out" +
233 " of range.\n")
234 return
235 if filename != "<string>":
236 break
237 # filename of "<string>" may mean that the function in question was
238 # defined dynamically and therefore its code stack is inaccessible.
239 # This may happen with functions like "rqprint_var". In this case,
240 # we'll increment the stack_frame_ix and try again.
241 stack_frame_ix += 1
242 if local_debug:
243 print("Adjusted stack_frame_ix...")
244 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500245
Michael Walsh1173a522018-05-21 17:24:51 -0500246 real_called_func_name = sprint_func_name(stack_frame_ix)
Michael Walsh23e7f492017-01-10 11:34:47 -0600247
248 module = inspect.getmodule(frame)
249
250 # Though I would expect inspect.getsourcelines(frame) to get all module
251 # source lines if the frame is "<module>", it doesn't do that. Therefore,
252 # for this special case, I will do inspect.getsourcelines(module).
253 if function_name == "<module>":
254 source_lines, source_line_num =\
255 inspect.getsourcelines(module)
256 line_ix = cur_line_no - source_line_num - 1
257 else:
258 source_lines, source_line_num =\
259 inspect.getsourcelines(frame)
260 line_ix = cur_line_no - source_line_num
261
262 if local_debug:
263 print("\n Variables retrieved from inspect.stack() function:")
264 print_varx("frame", frame, 0, debug_indent + 2)
265 print_varx("filename", filename, 0, debug_indent + 2)
266 print_varx("cur_line_no", cur_line_no, 0, debug_indent + 2)
267 print_varx("function_name", function_name, 0, debug_indent + 2)
268 print_varx("lines", lines, 0, debug_indent + 2)
269 print_varx("index", index, 0, debug_indent + 2)
270 print_varx("source_line_num", source_line_num, 0, debug_indent)
271 print_varx("line_ix", line_ix, 0, debug_indent)
272 if local_debug_show_source:
273 print_varx("source_lines", source_lines, 0, debug_indent)
Michael Walsh1173a522018-05-21 17:24:51 -0500274 print_varx("real_called_func_name", real_called_func_name, 0,
275 debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600276
277 # Get a list of all functions defined for the module. Note that this
278 # doesn't work consistently when _run_exitfuncs is at the top of the stack
279 # (i.e. if we're running an exit function). I've coded a work-around
280 # below for this deficiency.
281 all_functions = inspect.getmembers(module, inspect.isfunction)
282
283 # Get called_func_id by searching for our function in the list of all
284 # functions.
285 called_func_id = None
286 for func_name, function in all_functions:
Michael Walsh1173a522018-05-21 17:24:51 -0500287 if func_name == real_called_func_name:
Michael Walsh23e7f492017-01-10 11:34:47 -0600288 called_func_id = id(function)
289 break
290 # NOTE: The only time I've found that called_func_id can't be found is
291 # when we're running from an exit function.
292
293 # Look for other functions in module with matching id.
Michael Walsh1173a522018-05-21 17:24:51 -0500294 aliases = set([real_called_func_name])
Michael Walsh23e7f492017-01-10 11:34:47 -0600295 for func_name, function in all_functions:
Michael Walsh1173a522018-05-21 17:24:51 -0500296 if func_name == real_called_func_name:
Michael Walsh23e7f492017-01-10 11:34:47 -0600297 continue
298 func_id = id(function)
299 if func_id == called_func_id:
300 aliases.add(func_name)
301
302 # In most cases, my general purpose code above will find all aliases.
303 # However, for the odd case (i.e. running from exit function), I've added
304 # code to handle pvar, qpvar, dpvar, etc. aliases explicitly since they
305 # are defined in this module and used frequently.
306 # pvar is an alias for print_var.
Michael Walsh1173a522018-05-21 17:24:51 -0500307 aliases.add(re.sub("print_var", "pvar", real_called_func_name))
Michael Walsh23e7f492017-01-10 11:34:47 -0600308
Michael Walsh1173a522018-05-21 17:24:51 -0500309 func_name_regex = "(" + '|'.join(aliases) + ")"
310 pre_args_regex = ".*" + func_name_regex + "[ ]*\("
Michael Walsh23e7f492017-01-10 11:34:47 -0600311
312 # Search backward through source lines looking for the calling function
313 # name.
314 found = False
315 for start_line_ix in range(line_ix, 0, -1):
316 # Skip comment lines.
317 if re.match(r"[ ]*#", source_lines[start_line_ix]):
318 continue
Michael Walsh1173a522018-05-21 17:24:51 -0500319 if re.match(pre_args_regex, source_lines[start_line_ix]):
Michael Walsh23e7f492017-01-10 11:34:47 -0600320 found = True
321 break
322 if not found:
323 print_error("Programmer error - Could not find the source line with" +
Michael Walsh1173a522018-05-21 17:24:51 -0500324 " a reference to function \"" + real_called_func_name +
325 "\".\n")
Michael Walsh23e7f492017-01-10 11:34:47 -0600326 return
327
Michael Walsh82acf002017-05-04 14:33:05 -0500328 # Search forward through the source lines looking for a line whose
329 # indentation is the same or less than the start line. The end of our
330 # composite line should be the line preceding that line.
Michael Walsh1173a522018-05-21 17:24:51 -0500331 start_indent = get_line_indent(source_lines[start_line_ix])
Michael Walsh37cd29d2018-05-24 13:19:18 -0500332 end_line_ix = line_ix
Michael Walsh23e7f492017-01-10 11:34:47 -0600333 for end_line_ix in range(line_ix + 1, len(source_lines)):
334 if source_lines[end_line_ix].strip() == "":
335 continue
Michael Walsh1173a522018-05-21 17:24:51 -0500336 line_indent = get_line_indent(source_lines[end_line_ix])
Michael Walsh82acf002017-05-04 14:33:05 -0500337 if line_indent <= start_indent:
Michael Walsh23e7f492017-01-10 11:34:47 -0600338 end_line_ix -= 1
339 break
Michael Walsh1173a522018-05-21 17:24:51 -0500340 if start_line_ix != 0:
341 # Check to see whether the start line is a continuation of the prior
342 # line?
343 line_indent = get_line_indent(source_lines[start_line_ix - 1])
344 if line_indent < start_indent:
345 start_line_ix -= 1
346 # Remove the backslash (continuation char).
347 source_lines[start_line_ix] = re.sub(r"[ ]*\\([\r\n]$)",
348 " \\1",
349 source_lines[start_line_ix])
Michael Walsh23e7f492017-01-10 11:34:47 -0600350
351 # Join the start line through the end line into a composite line.
352 composite_line = ''.join(map(str.strip,
Gunnar Mills096cd562018-03-26 10:19:12 -0500353 source_lines[start_line_ix:end_line_ix + 1]))
Michael Walsh1173a522018-05-21 17:24:51 -0500354 # Insert one space after first "=" if there isn't one already.
355 composite_line = re.sub("=[ ]*([^ ])", "= \\1", composite_line, 1)
Michael Walsh7423c012016-10-04 10:27:21 -0500356
Michael Walsh1173a522018-05-21 17:24:51 -0500357 lvalue_regex = "[ ]+=[ ]*" + func_name_regex + ".*"
358 lvalue_string = re.sub(lvalue_regex, "", composite_line)
359 lvalues_list = map(str.strip, lvalue_string.split(","))
360 lvalues = collections.OrderedDict()
361 ix = len(lvalues_list) * -1
362 for lvalue in lvalues_list:
363 lvalues[ix] = lvalue
364 ix += 1
365 called_func_name = re.sub("(.*=)?[ ]+" + func_name_regex +
366 "[ ]*\(.*", "\\2",
367 composite_line)
368 arg_list_etc = "(" + re.sub(pre_args_regex, "", composite_line)
Michael Walshde791732016-09-06 14:25:24 -0500369 if local_debug:
Michael Walsh23e7f492017-01-10 11:34:47 -0600370 print_varx("aliases", aliases, 0, debug_indent)
Michael Walsh1173a522018-05-21 17:24:51 -0500371 print_varx("pre_args_regex", pre_args_regex, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600372 print_varx("start_line_ix", start_line_ix, 0, debug_indent)
373 print_varx("end_line_ix", end_line_ix, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500374 print_varx("composite_line", composite_line, 0, debug_indent)
Michael Walsh1173a522018-05-21 17:24:51 -0500375 print_varx("lvalue_regex", lvalue_regex, 0, debug_indent)
376 print_varx("lvalue_string", lvalue_string, 0, debug_indent)
377 print_varx("lvalues", lvalues, 0, debug_indent)
378 print_varx("called_func_name", called_func_name, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500379 print_varx("arg_list_etc", arg_list_etc, 0, debug_indent)
380
381 # Parse arg list...
382 # Initialize...
383 nest_level = -1
384 arg_ix = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500385 args_list = [""]
Michael Walshde791732016-09-06 14:25:24 -0500386 for ix in range(0, len(arg_list_etc)):
387 char = arg_list_etc[ix]
388 # Set the nest_level based on whether we've encounted a parenthesis.
389 if char == "(":
390 nest_level += 1
391 if nest_level == 0:
392 continue
393 elif char == ")":
394 nest_level -= 1
395 if nest_level < 0:
396 break
397
398 # If we reach a comma at base nest level, we are done processing an
Michael Walsh7423c012016-10-04 10:27:21 -0500399 # argument so we increment arg_ix and initialize a new args_list entry.
Michael Walshde791732016-09-06 14:25:24 -0500400 if char == "," and nest_level == 0:
401 arg_ix += 1
Michael Walsh7423c012016-10-04 10:27:21 -0500402 args_list.append("")
Michael Walshde791732016-09-06 14:25:24 -0500403 continue
404
Michael Walsh7423c012016-10-04 10:27:21 -0500405 # For any other character, we append it it to the current arg list
Michael Walshde791732016-09-06 14:25:24 -0500406 # entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500407 args_list[arg_ix] += char
Michael Walshde791732016-09-06 14:25:24 -0500408
409 # Trim whitespace from each list entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500410 args_list = [arg.strip() for arg in args_list]
Michael Walshde791732016-09-06 14:25:24 -0500411
Michael Walsh1173a522018-05-21 17:24:51 -0500412 if arg_num < 0:
413 if abs(arg_num) > len(lvalues):
414 argument = lvalues
415 else:
416 argument = lvalues[arg_num]
417 elif arg_num == 0:
418 argument = called_func_name
Michael Walsh2750b442018-05-18 14:49:11 -0500419 else:
Michael Walsh1173a522018-05-21 17:24:51 -0500420 if arg_num > len(args_list):
421 argument = args_list
422 else:
423 argument = args_list[arg_num - 1]
Michael Walshde791732016-09-06 14:25:24 -0500424
425 if local_debug:
Michael Walsh7423c012016-10-04 10:27:21 -0500426 print_varx("args_list", args_list, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500427 print_varx("argument", argument, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600428 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500429
430 return argument
431
Michael Walshde791732016-09-06 14:25:24 -0500432
Michael Walshde791732016-09-06 14:25:24 -0500433def sprint_time(buffer=""):
Michael Walshde791732016-09-06 14:25:24 -0500434 r"""
435 Return the time in the following format.
436
437 Example:
438
439 The following python code...
440
441 sys.stdout.write(sprint_time())
442 sys.stdout.write("Hi.\n")
443
444 Will result in the following type of output:
445
446 #(CDT) 2016/07/08 15:25:35 - Hi.
447
448 Example:
449
450 The following python code...
451
452 sys.stdout.write(sprint_time("Hi.\n"))
453
454 Will result in the following type of output:
455
456 #(CDT) 2016/08/03 17:12:05 - Hi.
457
458 The following environment variables will affect the formatting as
459 described:
460 NANOSECONDS This will cause the time stamps to be
461 precise to the microsecond (Yes, it
462 probably should have been named
463 MICROSECONDS but the convention was set
464 long ago so we're sticking with it).
465 Example of the output when environment
466 variable NANOSECONDS=1.
467
468 #(CDT) 2016/08/03 17:16:25.510469 - Hi.
469
470 SHOW_ELAPSED_TIME This will cause the elapsed time to be
471 included in the output. This is the
472 amount of time that has elapsed since the
473 last time this function was called. The
474 precision of the elapsed time field is
475 also affected by the value of the
476 NANOSECONDS environment variable. Example
477 of the output when environment variable
478 NANOSECONDS=0 and SHOW_ELAPSED_TIME=1.
479
480 #(CDT) 2016/08/03 17:17:40 - 0 - Hi.
481
482 Example of the output when environment variable NANOSECONDS=1 and
483 SHOW_ELAPSED_TIME=1.
484
485 #(CDT) 2016/08/03 17:18:47.317339 - 0.000046 - Hi.
486
487 Description of arguments.
488 buffer This will be appended to the formatted
489 time string.
490 """
491
492 global NANOSECONDS
493 global SHOW_ELAPSED_TIME
494 global sprint_time_last_seconds
495
496 seconds = time.time()
497 loc_time = time.localtime(seconds)
498 nanoseconds = "%0.6f" % seconds
499 pos = nanoseconds.find(".")
500 nanoseconds = nanoseconds[pos:]
501
502 time_string = time.strftime("#(%Z) %Y/%m/%d %H:%M:%S", loc_time)
503 if NANOSECONDS == "1":
504 time_string = time_string + nanoseconds
505
506 if SHOW_ELAPSED_TIME == "1":
507 cur_time_seconds = seconds
508 math_string = "%9.9f" % cur_time_seconds + " - " + "%9.9f" % \
509 sprint_time_last_seconds
510 elapsed_seconds = eval(math_string)
511 if NANOSECONDS == "1":
512 elapsed_seconds = "%11.6f" % elapsed_seconds
513 else:
514 elapsed_seconds = "%4i" % elapsed_seconds
515 sprint_time_last_seconds = cur_time_seconds
516 time_string = time_string + " - " + elapsed_seconds
517
518 return time_string + " - " + buffer
519
Michael Walshde791732016-09-06 14:25:24 -0500520
Michael Walshde791732016-09-06 14:25:24 -0500521def sprint_timen(buffer=""):
Michael Walshde791732016-09-06 14:25:24 -0500522 r"""
523 Append a line feed to the buffer, pass it to sprint_time and return the
524 result.
525 """
526
527 return sprint_time(buffer + "\n")
528
Michael Walshde791732016-09-06 14:25:24 -0500529
Michael Walshde791732016-09-06 14:25:24 -0500530def sprint_error(buffer=""):
Michael Walshde791732016-09-06 14:25:24 -0500531 r"""
532 Return a standardized error string. This includes:
533 - A time stamp
534 - The "**ERROR**" string
535 - The caller's buffer string.
536
537 Example:
538
539 The following python code...
540
541 print(sprint_error("Oops.\n"))
542
543 Will result in the following type of output:
544
545 #(CDT) 2016/08/03 17:12:05 - **ERROR** Oops.
546
547 Description of arguments.
548 buffer This will be appended to the formatted
549 error string.
550 """
551
552 return sprint_time() + "**ERROR** " + buffer
553
Michael Walshde791732016-09-06 14:25:24 -0500554
Michael Walshde791732016-09-06 14:25:24 -0500555def sprint_varx(var_name,
556 var_value,
557 hex=0,
558 loc_col1_indent=col1_indent,
Michael Walsh7423c012016-10-04 10:27:21 -0500559 loc_col1_width=col1_width,
Michael Walshd2869032018-03-22 16:12:11 -0500560 trailing_char="\n",
561 key_list=None):
Michael Walshde791732016-09-06 14:25:24 -0500562 r"""
563 Print the var name/value passed to it. If the caller lets loc_col1_width
564 default, the printing lines up nicely with output generated by the
565 print_time functions.
566
567 Note that the sprint_var function (defined below) can be used to call this
568 function so that the programmer does not need to pass the var_name.
569 sprint_var will figure out the var_name. The sprint_var function is the
570 one that would normally be used by the general user.
571
572 For example, the following python code:
573
574 first_name = "Mike"
575 print_time("Doing this...\n")
576 print_varx("first_name", first_name)
577 print_time("Doing that...\n")
578
579 Will generate output like this:
580
581 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this...
582 first_name: Mike
583 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that...
584
585 This function recognizes several complex types of data such as dict, list
586 or tuple.
587
588 For example, the following python code:
589
590 my_dict = dict(one=1, two=2, three=3)
591 print_var(my_dict)
592
593 Will generate the following output:
594
595 my_dict:
596 my_dict[three]: 3
597 my_dict[two]: 2
598 my_dict[one]: 1
599
600 Description of arguments.
601 var_name The name of the variable to be printed.
602 var_value The value of the variable to be printed.
603 hex This indicates that the value should be
604 printed in hex format. It is the user's
605 responsibility to ensure that a var_value
Michael Walshbec416d2016-11-10 08:54:52 -0600606 contains a valid hex number. For string
607 var_values, this will be interpreted as
608 show_blanks which means that blank values
Michael Walshd995cb02017-02-07 14:46:01 -0600609 will be printed as "<blank>". For dict
610 var_values, this will be interpreted as
611 terse format where keys are not repeated
612 in the output.
Michael Walshde791732016-09-06 14:25:24 -0500613 loc_col1_indent The number of spaces to indent the output.
614 loc_col1_width The width of the output column containing
615 the variable name. The default value of
616 this is adjusted so that the var_value
617 lines up with text printed via the
618 print_time function.
Michael Walsh7423c012016-10-04 10:27:21 -0500619 trailing_char The character to be used at the end of the
620 returned string. The default value is a
621 line feed.
Michael Walshd2869032018-03-22 16:12:11 -0500622 key_list A list of which dictionary keys should be
623 printed. All others keys will be skipped.
624 Each value in key_list will be regarded
625 as a regular expression and it will be
626 regarded as anchored to the beginning and
627 ends of the dictionary key being
628 referenced. For example if key_list is
629 ["one", "two"], the resulting regex used
630 will be "^one|two$", i.e. only keys "one"
631 and "two" from the var_value dictionary
632 will be printed. As another example, if
633 the caller were to specify a key_list of
634 ["one.*"], then only dictionary keys whose
635 names begin with "one" will be printed.
636 Note: This argument pertains only to
637 var_values which are dictionaries.
Michael Walsh7423c012016-10-04 10:27:21 -0500638 """
Michael Walshde791732016-09-06 14:25:24 -0500639
640 # Determine the type
Michael Walsh92ac3d02018-03-30 14:38:15 -0500641 if type(var_value) in (int, long, float, bool, str, unicode) \
Michael Walshde791732016-09-06 14:25:24 -0500642 or var_value is None:
643 # The data type is simple in the sense that it has no subordinate
644 # parts.
Michael Walsh7423c012016-10-04 10:27:21 -0500645 # Adjust loc_col1_width.
646 loc_col1_width = loc_col1_width - loc_col1_indent
Michael Walshde791732016-09-06 14:25:24 -0500647 # See if the user wants the output in hex format.
648 if hex:
Michael Walsh18176322016-11-15 15:11:21 -0600649 if type(var_value) not in (int, long):
Michael Walshbec416d2016-11-10 08:54:52 -0600650 value_format = "%s"
Michael Walsh2795edc2016-12-13 16:00:33 -0600651 if var_value == "":
Michael Walshbec416d2016-11-10 08:54:52 -0600652 var_value = "<blank>"
653 else:
Michael Walsh92ac3d02018-03-30 14:38:15 -0500654 if type(var_value) is long or var_value >= 0x100000000:
655 value_format = "0x%16x"
656 else:
657 value_format = "0x%08x"
Michael Walshde791732016-09-06 14:25:24 -0500658 else:
659 value_format = "%s"
660 format_string = "%" + str(loc_col1_indent) + "s%-" \
Michael Walsh7423c012016-10-04 10:27:21 -0500661 + str(loc_col1_width) + "s" + value_format + trailing_char
Michael Walsh3383e652017-09-01 17:10:59 -0500662 if value_format == "0x%08x":
663 return format_string % ("", str(var_name) + ":",
664 var_value & 0xffffffff)
665 else:
666 return format_string % ("", str(var_name) + ":", var_value)
Michael Walsh20a87ab2017-06-30 17:00:30 -0500667 elif type(var_value) is type:
668 return sprint_varx(var_name, str(var_value).split("'")[1], hex,
Michael Walshd2869032018-03-22 16:12:11 -0500669 loc_col1_indent, loc_col1_width, trailing_char,
670 key_list)
Michael Walshde791732016-09-06 14:25:24 -0500671 else:
672 # The data type is complex in the sense that it has subordinate parts.
673 format_string = "%" + str(loc_col1_indent) + "s%s\n"
674 buffer = format_string % ("", var_name + ":")
675 loc_col1_indent += 2
Michael Walsh7423c012016-10-04 10:27:21 -0500676 try:
677 length = len(var_value)
678 except TypeError:
Michael Walsh23e7f492017-01-10 11:34:47 -0600679 length = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500680 ix = 0
681 loc_trailing_char = "\n"
Michael Walshbec416d2016-11-10 08:54:52 -0600682 type_is_dict = 0
Michael Walsh23e7f492017-01-10 11:34:47 -0600683 if type(var_value) is dict:
684 type_is_dict = 1
Michael Walsh8e6deb42017-01-27 14:22:41 -0600685 try:
686 if type(var_value) is collections.OrderedDict:
687 type_is_dict = 1
688 except AttributeError:
689 pass
690 try:
691 if type(var_value) is DotDict:
692 type_is_dict = 1
693 except NameError:
694 pass
695 try:
696 if type(var_value) is NormalizedDict:
697 type_is_dict = 1
698 except NameError:
699 pass
Michael Walshbec416d2016-11-10 08:54:52 -0600700 if type_is_dict:
Michael Walshde791732016-09-06 14:25:24 -0500701 for key, value in var_value.iteritems():
Michael Walshd2869032018-03-22 16:12:11 -0500702 if key_list is not None:
703 key_list_regex = "^" + "|".join(key_list) + "$"
704 if not re.match(key_list_regex, key):
705 continue
Michael Walsh7423c012016-10-04 10:27:21 -0500706 ix += 1
707 if ix == length:
708 loc_trailing_char = trailing_char
Michael Walshd995cb02017-02-07 14:46:01 -0600709 if hex:
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600710 # Since hex is being used as a format type, we want it
711 # turned off when processing integer dictionary values so
712 # it is not interpreted as a hex indicator.
713 loc_hex = not (type(value) is int)
Michael Walshf7b8a002017-08-29 10:38:39 -0500714 buffer += sprint_varx("[" + key + "]", value,
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600715 loc_hex, loc_col1_indent,
716 loc_col1_width,
Michael Walshd2869032018-03-22 16:12:11 -0500717 loc_trailing_char,
718 key_list)
Michael Walshd995cb02017-02-07 14:46:01 -0600719 else:
Michael Walsh1173a522018-05-21 17:24:51 -0500720 buffer += sprint_varx(var_name + "[" + str(key) + "]",
721 value, hex, loc_col1_indent,
722 loc_col1_width, loc_trailing_char,
723 key_list)
Michael Walsh7423c012016-10-04 10:27:21 -0500724 elif type(var_value) in (list, tuple, set):
Michael Walshde791732016-09-06 14:25:24 -0500725 for key, value in enumerate(var_value):
Michael Walsh7423c012016-10-04 10:27:21 -0500726 ix += 1
727 if ix == length:
728 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -0500729 buffer += sprint_varx(var_name + "[" + str(key) + "]", value,
Michael Walsh7423c012016-10-04 10:27:21 -0500730 hex, loc_col1_indent, loc_col1_width,
Michael Walshd2869032018-03-22 16:12:11 -0500731 loc_trailing_char, key_list)
Michael Walshde791732016-09-06 14:25:24 -0500732 elif type(var_value) is argparse.Namespace:
733 for key in var_value.__dict__:
Michael Walsh7423c012016-10-04 10:27:21 -0500734 ix += 1
735 if ix == length:
736 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -0500737 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \
Michael Walsh7423c012016-10-04 10:27:21 -0500738 + ", var_value." + key + ", hex, loc_col1_indent," \
Michael Walshd2869032018-03-22 16:12:11 -0500739 + " loc_col1_width, loc_trailing_char, key_list)"
Michael Walshde791732016-09-06 14:25:24 -0500740 exec(cmd_buf)
741 else:
742 var_type = type(var_value).__name__
743 func_name = sys._getframe().f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -0500744 var_value = "<" + var_type + " type not supported by " + \
745 func_name + "()>"
Michael Walshde791732016-09-06 14:25:24 -0500746 value_format = "%s"
747 loc_col1_indent -= 2
Michael Walsh7423c012016-10-04 10:27:21 -0500748 # Adjust loc_col1_width.
749 loc_col1_width = loc_col1_width - loc_col1_indent
Michael Walshde791732016-09-06 14:25:24 -0500750 format_string = "%" + str(loc_col1_indent) + "s%-" \
Michael Walsh7423c012016-10-04 10:27:21 -0500751 + str(loc_col1_width) + "s" + value_format + trailing_char
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600752 return format_string % ("", str(var_name) + ":", var_value)
Michael Walsh23e7f492017-01-10 11:34:47 -0600753
Michael Walshde791732016-09-06 14:25:24 -0500754 return buffer
755
756 return ""
757
Michael Walshde791732016-09-06 14:25:24 -0500758
Michael Walshfd2733c2017-11-13 11:36:20 -0600759def sprint_var(var_value,
760 hex=0,
761 loc_col1_indent=col1_indent,
762 loc_col1_width=col1_width,
Michael Walshd2869032018-03-22 16:12:11 -0500763 trailing_char="\n",
764 key_list=None):
Michael Walshde791732016-09-06 14:25:24 -0500765 r"""
766 Figure out the name of the first argument for you and then call
767 sprint_varx with it. Therefore, the following 2 calls are equivalent:
768 sprint_varx("var1", var1)
769 sprint_var(var1)
770 """
771
772 # Get the name of the first variable passed to this function.
773 stack_frame = 2
Michael Walsh7423c012016-10-04 10:27:21 -0500774 caller_func_name = sprint_func_name(2)
775 if caller_func_name.endswith("print_var"):
Michael Walshde791732016-09-06 14:25:24 -0500776 stack_frame += 1
777 var_name = get_arg_name(None, 1, stack_frame)
Michael Walshfd2733c2017-11-13 11:36:20 -0600778 return sprint_varx(var_name, var_value=var_value, hex=hex,
779 loc_col1_indent=loc_col1_indent,
780 loc_col1_width=loc_col1_width,
Michael Walshd2869032018-03-22 16:12:11 -0500781 trailing_char=trailing_char,
782 key_list=key_list)
Michael Walshde791732016-09-06 14:25:24 -0500783
784
Michael Walsh18176322016-11-15 15:11:21 -0600785def sprint_vars(*args):
Michael Walsh18176322016-11-15 15:11:21 -0600786 r"""
787 Sprint the values of one or more variables.
788
789 Description of args:
790 args:
791 If the first argument is an integer, it will be interpreted to be the
792 "indent" value.
793 If the second argument is an integer, it will be interpreted to be the
794 "col1_width" value.
795 If the third argument is an integer, it will be interpreted to be the
796 "hex" value.
797 All remaining parms are considered variable names which are to be
798 sprinted.
799 """
800
801 if len(args) == 0:
802 return
803
804 # Get the name of the first variable passed to this function.
805 stack_frame = 2
806 caller_func_name = sprint_func_name(2)
807 if caller_func_name.endswith("print_vars"):
808 stack_frame += 1
809
810 parm_num = 1
811
812 # Create list from args (which is a tuple) so that it can be modified.
813 args_list = list(args)
814
815 var_name = get_arg_name(None, parm_num, stack_frame)
816 # See if parm 1 is to be interpreted as "indent".
817 try:
818 if type(int(var_name)) is int:
819 indent = int(var_name)
820 args_list.pop(0)
821 parm_num += 1
822 except ValueError:
823 indent = 0
824
825 var_name = get_arg_name(None, parm_num, stack_frame)
826 # See if parm 1 is to be interpreted as "col1_width".
827 try:
828 if type(int(var_name)) is int:
829 loc_col1_width = int(var_name)
830 args_list.pop(0)
831 parm_num += 1
832 except ValueError:
833 loc_col1_width = col1_width
834
835 var_name = get_arg_name(None, parm_num, stack_frame)
836 # See if parm 1 is to be interpreted as "hex".
837 try:
838 if type(int(var_name)) is int:
839 hex = int(var_name)
840 args_list.pop(0)
841 parm_num += 1
842 except ValueError:
843 hex = 0
844
845 buffer = ""
846 for var_value in args_list:
847 var_name = get_arg_name(None, parm_num, stack_frame)
848 buffer += sprint_varx(var_name, var_value, hex, indent, loc_col1_width)
849 parm_num += 1
850
851 return buffer
852
Michael Walsh18176322016-11-15 15:11:21 -0600853
Michael Walsh7423c012016-10-04 10:27:21 -0500854def sprint_dashes(indent=col1_indent,
855 width=80,
856 line_feed=1,
857 char="-"):
Michael Walshde791732016-09-06 14:25:24 -0500858 r"""
859 Return a string of dashes to the caller.
860
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600861 Description of arguments:
Michael Walshde791732016-09-06 14:25:24 -0500862 indent The number of characters to indent the
863 output.
864 width The width of the string of dashes.
865 line_feed Indicates whether the output should end
866 with a line feed.
Michael Walsh7423c012016-10-04 10:27:21 -0500867 char The character to be repeated in the output
868 string.
Michael Walshde791732016-09-06 14:25:24 -0500869 """
870
Michael Walsh7423c012016-10-04 10:27:21 -0500871 width = int(width)
Michael Walsh23e7f492017-01-10 11:34:47 -0600872 buffer = " " * int(indent) + char * width
Michael Walshde791732016-09-06 14:25:24 -0500873 if line_feed:
874 buffer += "\n"
875
876 return buffer
877
Michael Walshde791732016-09-06 14:25:24 -0500878
Michael Walsh7423c012016-10-04 10:27:21 -0500879def sindent(text="",
880 indent=0):
Michael Walsh7423c012016-10-04 10:27:21 -0500881 r"""
882 Pre-pend the specified number of characters to the text string (i.e.
883 indent it) and return it.
884
885 Description of arguments:
886 text The string to be indented.
887 indent The number of characters to indent the
888 string.
889 """
890
891 format_string = "%" + str(indent) + "s%s"
892 buffer = format_string % ("", text)
893
894 return buffer
895
Michael Walsh7423c012016-10-04 10:27:21 -0500896
Michael Walsh7423c012016-10-04 10:27:21 -0500897def sprint_call_stack(indent=0,
898 stack_frame_ix=0):
Michael Walshde791732016-09-06 14:25:24 -0500899 r"""
900 Return a call stack report for the given point in the program with line
901 numbers, function names and function parameters and arguments.
902
903 Sample output:
904
905 -------------------------------------------------------------------------
906 Python function call stack
907
908 Line # Function name and arguments
909 ------ ------------------------------------------------------------------
910 424 sprint_call_stack ()
911 4 print_call_stack ()
912 31 func1 (last_name = 'walsh', first_name = 'mikey')
913 59 /tmp/scr5.py
914 -------------------------------------------------------------------------
915
916 Description of arguments:
917 indent The number of characters to indent each
918 line of output.
919 stack_frame_ix The index of the first stack frame which
920 is to be returned.
921 """
922
923 buffer = ""
Michael Walsh7423c012016-10-04 10:27:21 -0500924 buffer += sprint_dashes(indent)
925 buffer += sindent("Python function call stack\n\n", indent)
926 buffer += sindent("Line # Function name and arguments\n", indent)
927 buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73)
Michael Walshde791732016-09-06 14:25:24 -0500928
929 # Grab the current program stack.
930 current_stack = inspect.stack()
931
932 # Process each frame in turn.
933 format_string = "%6s %s\n"
Michael Walsh7423c012016-10-04 10:27:21 -0500934 ix = 0
Michael Walshde791732016-09-06 14:25:24 -0500935 for stack_frame in current_stack:
Michael Walsh7423c012016-10-04 10:27:21 -0500936 if ix < stack_frame_ix:
937 ix += 1
938 continue
Michael Walsh23e7f492017-01-10 11:34:47 -0600939 # I want the line number shown to be the line where you find the line
940 # shown.
941 try:
942 line_num = str(current_stack[ix + 1][2])
943 except IndexError:
944 line_num = ""
Michael Walshde791732016-09-06 14:25:24 -0500945 func_name = str(stack_frame[3])
946 if func_name == "?":
947 # "?" is the name used when code is not in a function.
948 func_name = "(none)"
949
950 if func_name == "<module>":
Michael Walsh7423c012016-10-04 10:27:21 -0500951 # If the func_name is the "main" program, we simply get the
952 # command line call string.
Michael Walshde791732016-09-06 14:25:24 -0500953 func_and_args = ' '.join(sys.argv)
954 else:
955 # Get the program arguments.
956 arg_vals = inspect.getargvalues(stack_frame[0])
957 function_parms = arg_vals[0]
958 frame_locals = arg_vals[3]
959
Michael Walsh7423c012016-10-04 10:27:21 -0500960 args_list = []
Michael Walshde791732016-09-06 14:25:24 -0500961 for arg_name in function_parms:
962 # Get the arg value from frame locals.
963 arg_value = frame_locals[arg_name]
Michael Walsh7423c012016-10-04 10:27:21 -0500964 args_list.append(arg_name + " = " + repr(arg_value))
965 args_str = "(" + ', '.join(map(str, args_list)) + ")"
Michael Walshde791732016-09-06 14:25:24 -0500966
967 # Now we need to print this in a nicely-wrapped way.
968 func_and_args = func_name + " " + args_str
969
Michael Walsh23e7f492017-01-10 11:34:47 -0600970 buffer += sindent(format_string % (line_num, func_and_args), indent)
Michael Walsh7423c012016-10-04 10:27:21 -0500971 ix += 1
Michael Walshde791732016-09-06 14:25:24 -0500972
Michael Walsh7423c012016-10-04 10:27:21 -0500973 buffer += sprint_dashes(indent)
Michael Walshde791732016-09-06 14:25:24 -0500974
975 return buffer
976
Michael Walshde791732016-09-06 14:25:24 -0500977
Michael Walshde791732016-09-06 14:25:24 -0500978def sprint_executing(stack_frame_ix=None):
Michael Walshde791732016-09-06 14:25:24 -0500979 r"""
980 Print a line indicating what function is executing and with what parameter
981 values. This is useful for debugging.
982
983 Sample output:
984
985 #(CDT) 2016/08/25 17:54:27 - Executing: func1 (x = 1)
986
987 Description of arguments:
988 stack_frame_ix The index of the stack frame whose
989 function info should be returned. If the
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600990 caller does not specify a value, this
Michael Walshde791732016-09-06 14:25:24 -0500991 function will set the value to 1 which is
992 the index of the caller's stack frame. If
993 the caller is the wrapper function
994 "print_executing", this function will bump
995 it up by 1.
996 """
997
998 # If user wants default stack_frame_ix.
999 if stack_frame_ix is None:
1000 func_name = sys._getframe().f_code.co_name
1001 caller_func_name = sys._getframe(1).f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -05001002 if caller_func_name.endswith(func_name[1:]):
Michael Walshde791732016-09-06 14:25:24 -05001003 stack_frame_ix = 2
1004 else:
1005 stack_frame_ix = 1
1006
1007 stack_frame = inspect.stack()[stack_frame_ix]
1008
1009 func_name = str(stack_frame[3])
1010 if func_name == "?":
1011 # "?" is the name used when code is not in a function.
1012 func_name = "(none)"
1013
1014 if func_name == "<module>":
1015 # If the func_name is the "main" program, we simply get the command
1016 # line call string.
1017 func_and_args = ' '.join(sys.argv)
1018 else:
1019 # Get the program arguments.
1020 arg_vals = inspect.getargvalues(stack_frame[0])
1021 function_parms = arg_vals[0]
1022 frame_locals = arg_vals[3]
1023
Michael Walsh7423c012016-10-04 10:27:21 -05001024 args_list = []
Michael Walshde791732016-09-06 14:25:24 -05001025 for arg_name in function_parms:
1026 # Get the arg value from frame locals.
1027 arg_value = frame_locals[arg_name]
Michael Walsh7423c012016-10-04 10:27:21 -05001028 args_list.append(arg_name + " = " + repr(arg_value))
1029 args_str = "(" + ', '.join(map(str, args_list)) + ")"
Michael Walshde791732016-09-06 14:25:24 -05001030
1031 # Now we need to print this in a nicely-wrapped way.
1032 func_and_args = func_name + " " + args_str
1033
1034 return sprint_time() + "Executing: " + func_and_args + "\n"
1035
Michael Walshde791732016-09-06 14:25:24 -05001036
Michael Walshbec416d2016-11-10 08:54:52 -06001037def sprint_pgm_header(indent=0,
1038 linefeed=1):
Michael Walshde791732016-09-06 14:25:24 -05001039 r"""
1040 Return a standardized header that programs should print at the beginning
1041 of the run. It includes useful information like command line, pid,
1042 userid, program parameters, etc.
1043
Michael Walsh7423c012016-10-04 10:27:21 -05001044 Description of arguments:
1045 indent The number of characters to indent each
1046 line of output.
Michael Walshbec416d2016-11-10 08:54:52 -06001047 linefeed Indicates whether a line feed be included
1048 at the beginning and end of the report.
Michael Walshde791732016-09-06 14:25:24 -05001049 """
1050
Michael Walshbec416d2016-11-10 08:54:52 -06001051 loc_col1_width = col1_width + indent
1052
1053 buffer = ""
1054 if linefeed:
1055 buffer = "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001056
Michael Walshdb6e68a2017-05-23 17:55:31 -05001057 if robot_env:
1058 suite_name = BuiltIn().get_variable_value("${suite_name}")
1059 buffer += sindent(sprint_time("Running test suite \"" + suite_name +
Gunnar Mills096cd562018-03-26 10:19:12 -05001060 "\".\n"), indent)
Michael Walshdb6e68a2017-05-23 17:55:31 -05001061
Michael Walsh7423c012016-10-04 10:27:21 -05001062 buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent)
1063 buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n",
1064 indent)
Michael Walshbec416d2016-11-10 08:54:52 -06001065 buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent,
1066 loc_col1_width)
Michael Walsh7423c012016-10-04 10:27:21 -05001067 # We want the output to show a customized name for the pid and pgid but
1068 # we want it to look like a valid variable name. Therefore, we'll use
Michael Walshde791732016-09-06 14:25:24 -05001069 # pgm_name_var_name which was set when this module was imported.
Michael Walshbec416d2016-11-10 08:54:52 -06001070 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent,
1071 loc_col1_width)
1072 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent,
1073 loc_col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001074 userid_num = str(os.geteuid())
1075 try:
1076 username = os.getlogin()
1077 except OSError:
1078 if userid_num == "0":
1079 username = "root"
1080 else:
1081 username = "?"
1082 buffer += sprint_varx("uid", userid_num + " (" + username +
Michael Walshbec416d2016-11-10 08:54:52 -06001083 ")", 0, indent, loc_col1_width)
Michael Walshde791732016-09-06 14:25:24 -05001084 buffer += sprint_varx("gid", str(os.getgid()) + " (" +
Michael Walsh7423c012016-10-04 10:27:21 -05001085 str(grp.getgrgid(os.getgid()).gr_name) + ")", 0,
Michael Walshbec416d2016-11-10 08:54:52 -06001086 indent, loc_col1_width)
1087 buffer += sprint_varx("host_name", socket.gethostname(), 0, indent,
1088 loc_col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001089 try:
1090 DISPLAY = os.environ['DISPLAY']
1091 except KeyError:
1092 DISPLAY = ""
1093 buffer += sprint_varx("DISPLAY", DISPLAY, 0, indent,
Michael Walshbec416d2016-11-10 08:54:52 -06001094 loc_col1_width)
Michael Walshde791732016-09-06 14:25:24 -05001095 # I want to add code to print caller's parms.
1096
Michael Walsh7423c012016-10-04 10:27:21 -05001097 # __builtin__.arg_obj is created by the get_arg module function,
1098 # gen_get_options.
1099 try:
1100 buffer += ga.sprint_args(__builtin__.arg_obj, indent)
1101 except AttributeError:
1102 pass
1103
Michael Walshdb6e68a2017-05-23 17:55:31 -05001104 if robot_env:
1105 # Get value of global parm_list.
1106 parm_list = BuiltIn().get_variable_value("${parm_list}")
1107
1108 for parm in parm_list:
1109 parm_value = BuiltIn().get_variable_value("${" + parm + "}")
1110 buffer += sprint_varx(parm, parm_value, 0, indent, loc_col1_width)
1111
1112 # Setting global program_pid.
1113 BuiltIn().set_global_variable("${program_pid}", os.getpid())
1114
Michael Walshbec416d2016-11-10 08:54:52 -06001115 if linefeed:
1116 buffer += "\n"
Michael Walshde791732016-09-06 14:25:24 -05001117
1118 return buffer
1119
Michael Walshde791732016-09-06 14:25:24 -05001120
Michael Walsh7423c012016-10-04 10:27:21 -05001121def sprint_error_report(error_text="\n",
Michael Walshdb6e68a2017-05-23 17:55:31 -05001122 indent=2,
1123 format=None):
Michael Walsh7423c012016-10-04 10:27:21 -05001124 r"""
1125 Return a string with a standardized report which includes the caller's
1126 error text, the call stack and the program header.
1127
1128 Description of args:
1129 error_text The error text to be included in the
1130 report. The caller should include any
1131 needed linefeeds.
1132 indent The number of characters to indent each
1133 line of output.
Michael Walshdb6e68a2017-05-23 17:55:31 -05001134 format Long or short format. Long includes
1135 extras like lines of dashes, call stack,
1136 etc.
Michael Walsh7423c012016-10-04 10:27:21 -05001137 """
1138
Michael Walshdb6e68a2017-05-23 17:55:31 -05001139 # Process input.
1140 indent = int(indent)
1141 if format is None:
1142 if robot_env:
1143 format = 'short'
1144 else:
1145 format = 'long'
1146 error_text = error_text.rstrip('\n') + '\n'
1147
1148 if format == 'short':
1149 return sprint_error(error_text)
1150
Michael Walsh7423c012016-10-04 10:27:21 -05001151 buffer = ""
1152 buffer += sprint_dashes(width=120, char="=")
1153 buffer += sprint_error(error_text)
1154 buffer += "\n"
1155 # Calling sprint_call_stack with stack_frame_ix of 0 causes it to show
1156 # itself and this function in the call stack. This is not helpful to a
1157 # debugger and is therefore clutter. We will adjust the stack_frame_ix to
1158 # hide that information.
Michael Walsh9c75f672017-09-12 17:11:35 -05001159 stack_frame_ix = 1
Michael Walsh7423c012016-10-04 10:27:21 -05001160 caller_func_name = sprint_func_name(2)
1161 if caller_func_name.endswith("print_error_report"):
1162 stack_frame_ix += 1
Michael Walshdb6e68a2017-05-23 17:55:31 -05001163 if not robot_env:
1164 buffer += sprint_call_stack(indent, stack_frame_ix)
Michael Walsh7423c012016-10-04 10:27:21 -05001165 buffer += sprint_pgm_header(indent)
1166 buffer += sprint_dashes(width=120, char="=")
1167
1168 return buffer
1169
Michael Walsh7423c012016-10-04 10:27:21 -05001170
Michael Walsh18176322016-11-15 15:11:21 -06001171def sprint_issuing(cmd_buf,
1172 test_mode=0):
Michael Walshde791732016-09-06 14:25:24 -05001173 r"""
1174 Return a line indicating a command that the program is about to execute.
1175
1176 Sample output for a cmd_buf of "ls"
1177
1178 #(CDT) 2016/08/25 17:57:36 - Issuing: ls
Michael Walshbec416d2016-11-10 08:54:52 -06001179
Michael Walshde791732016-09-06 14:25:24 -05001180 Description of args:
1181 cmd_buf The command to be executed by caller.
Michael Walshbec416d2016-11-10 08:54:52 -06001182 test_mode With test_mode set, your output will look
1183 like this:
1184
1185 #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls
1186
Michael Walshde791732016-09-06 14:25:24 -05001187 """
1188
Michael Walshbec416d2016-11-10 08:54:52 -06001189 buffer = sprint_time()
1190 if test_mode:
1191 buffer += "(test_mode) "
1192 buffer += "Issuing: " + cmd_buf + "\n"
Michael Walshde791732016-09-06 14:25:24 -05001193
1194 return buffer
1195
Michael Walshde791732016-09-06 14:25:24 -05001196
Michael Walshde791732016-09-06 14:25:24 -05001197def sprint_pgm_footer():
Michael Walshde791732016-09-06 14:25:24 -05001198 r"""
1199 Return a standardized footer that programs should print at the end of the
1200 program run. It includes useful information like total run time, etc.
1201 """
1202
1203 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n"
1204
1205 total_time = time.time() - start_time
1206 total_time_string = "%0.6f" % total_time
1207
Michael Walsh7423c012016-10-04 10:27:21 -05001208 buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string)
Michael Walshbec416d2016-11-10 08:54:52 -06001209 buffer += "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001210
1211 return buffer
1212
Michael Walsh7423c012016-10-04 10:27:21 -05001213
Michael Walsh7423c012016-10-04 10:27:21 -05001214def sprint(buffer=""):
Michael Walsh7423c012016-10-04 10:27:21 -05001215 r"""
1216 Simply return the user's buffer. This function is used by the qprint and
1217 dprint functions defined dynamically below, i.e. it would not normally be
1218 called for general use.
1219
1220 Description of arguments.
1221 buffer This will be returned to the caller.
1222 """
Michael Walshde791732016-09-06 14:25:24 -05001223
Michael Walsh95e45102018-02-09 12:44:43 -06001224 try:
1225 return str(buffer)
1226 except UnicodeEncodeError:
1227 return buffer
Michael Walshbec416d2016-11-10 08:54:52 -06001228
Michael Walshbec416d2016-11-10 08:54:52 -06001229
Michael Walshbec416d2016-11-10 08:54:52 -06001230def sprintn(buffer=""):
Michael Walshbec416d2016-11-10 08:54:52 -06001231 r"""
1232 Simply return the user's buffer with a line feed. This function is used
1233 by the qprint and dprint functions defined dynamically below, i.e. it
1234 would not normally be called for general use.
1235
1236 Description of arguments.
1237 buffer This will be returned to the caller.
1238 """
1239
Michael Walsh95e45102018-02-09 12:44:43 -06001240 try:
1241 buffer = str(buffer) + "\n"
1242 except UnicodeEncodeError:
1243 buffer = buffer + "\n"
Michael Walshbec416d2016-11-10 08:54:52 -06001244
Michael Walshde791732016-09-06 14:25:24 -05001245 return buffer
1246
Michael Walsh168eb0f2017-12-01 15:35:32 -06001247
Michael Walshfd2733c2017-11-13 11:36:20 -06001248def gp_print(buffer,
1249 stream='stdout'):
Michael Walshfd2733c2017-11-13 11:36:20 -06001250 r"""
1251 Print the buffer using either sys.stdout.write or BuiltIn().log_to_console
1252 depending on whether we are running in a robot environment.
1253
1254 This function is intended for use only by other functions in this module.
1255
1256 Description of arguments:
1257 buffer The string to be printed.
1258 stream Either "stdout" or "stderr".
1259 """
1260
1261 if robot_env:
1262 BuiltIn().log_to_console(buffer, stream=stream, no_newline=True)
1263 else:
1264 if stream == "stdout":
1265 sys.stdout.write(buffer)
1266 sys.stdout.flush()
1267 else:
1268 sys.stderr.write(buffer)
1269 sys.stderr.flush()
Michael Walshde791732016-09-06 14:25:24 -05001270
1271
Michael Walsh168eb0f2017-12-01 15:35:32 -06001272def gp_log(buffer):
Michael Walsh168eb0f2017-12-01 15:35:32 -06001273 r"""
1274 Log the buffer using either python logging or BuiltIn().log depending on
1275 whether we are running in a robot environment.
1276
1277 This function is intended for use only by other functions in this module.
1278
1279 Description of arguments:
1280 buffer The string to be logged.
1281 """
1282
1283 if robot_env:
1284 BuiltIn().log(buffer)
1285 else:
1286 logging.warning(buffer)
1287
1288
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001289def gp_debug_print(buffer):
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001290 r"""
Michael Walshfd2733c2017-11-13 11:36:20 -06001291 Print with gp_print only if gen_print_debug is set.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001292
1293 This function is intended for use only by other functions in this module.
1294
1295 Description of arguments:
1296 buffer The string to be printed.
1297 """
1298
1299 if not gen_print_debug:
1300 return
1301
Michael Walshfd2733c2017-11-13 11:36:20 -06001302 gp_print(buffer)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001303
1304
Michael Walshb1500152017-04-12 15:42:43 -05001305def get_var_value(var_value=None,
1306 default=1,
1307 var_name=None):
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001308 r"""
Michael Walshb1500152017-04-12 15:42:43 -05001309 Return either var_value, the corresponding global value or default.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001310
Michael Walshb1500152017-04-12 15:42:43 -05001311 If var_value is not None, it will simply be returned.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001312
Michael Walshb1500152017-04-12 15:42:43 -05001313 If var_value is None, this function will return the corresponding global
1314 value of the variable in question.
1315
1316 Note: For global values, if we are in a robot environment,
1317 get_variable_value will be used. Otherwise, the __builtin__ version of
1318 the variable is returned (which are set by gen_arg.py functions).
1319
1320 If there is no global value associated with the variable, default is
1321 returned.
1322
1323 This function is useful for other functions in setting default values for
1324 parameters.
1325
1326 Example use:
1327
1328 def my_func(quiet=None):
1329
1330 quiet = int(get_var_value(quiet, 0))
1331
1332 Example calls to my_func():
1333
1334 In the following example, the caller is explicitly asking to have quiet be
1335 set to 1.
1336
1337 my_func(quiet=1)
1338
1339 In the following example, quiet will be set to the global value of quiet,
1340 if defined, or to 0 (the default).
1341
1342 my_func()
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001343
1344 Description of arguments:
Michael Walshb1500152017-04-12 15:42:43 -05001345 var_value The value to be returned (if not equal to
1346 None).
1347 default The value that is returned if var_value is
1348 None and there is no corresponding global
1349 value defined.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001350 var_name The name of the variable whose value is to
Michael Walshb1500152017-04-12 15:42:43 -05001351 be returned. Under most circumstances,
1352 this value need not be provided. This
1353 function can figure out the name of the
1354 variable passed as var_value. One
1355 exception to this would be if this
1356 function is called directly from a .robot
1357 file.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001358 """
1359
Michael Walshb1500152017-04-12 15:42:43 -05001360 if var_value is not None:
1361 return var_value
1362
1363 if var_name is None:
1364 var_name = get_arg_name(None, 1, 2)
1365
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001366 if robot_env:
Michael Walshc6537442017-06-06 15:33:52 -05001367 var_value = BuiltIn().get_variable_value("${" + var_name + "}",
1368 default)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001369 else:
1370 var_value = getattr(__builtin__, var_name, default)
1371
1372 return var_value
1373
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001374
Michael Walsh052ff812018-05-18 16:09:09 -05001375def get_stack_var(var_name,
1376 default="",
1377 init_stack_ix=2):
1378
1379 r"""
1380 Starting with the caller's stack level, search upward in the call stack,
1381 for a variable named var_name and return its value. If the variable
1382 cannot be found, return default.
1383
1384 Example code:
1385
1386 def func12():
1387 my_loc_var1 = get_stack_var('my_var1', "default value")
1388
1389 def func11():
1390 my_var1 = 11
1391 func12()
1392
1393 In this example, get_stack_var will find the value of my_var1 in func11's
1394 stack and will therefore return the value 11. Therefore, my_loc_var1
1395 would get set to 11.
1396
1397 Description of argument(s):
1398 var_name The name of the variable to be searched
1399 for.
1400 default The value to return if the the variable
1401 cannot be found.
1402 init_stack_ix The initial stack index from which to
1403 begin the search. 0 would be the index of
1404 this func1tion ("get_stack_var"), 1 would
1405 be the index of the function calling this
1406 function, etc.
1407 """
1408
1409 return next((frame[0].f_locals[var_name]
1410 for frame in inspect.stack()[init_stack_ix:]
1411 if var_name in frame[0].f_locals), default)
1412
1413
Michael Walsh82acf002017-05-04 14:33:05 -05001414# hidden_text is a list of passwords which are to be replaced with asterisks
1415# by print functions defined in this module.
1416hidden_text = []
1417# password_regex is created based on the contents of hidden_text.
1418password_regex = ""
1419
1420
Michael Walsh82acf002017-05-04 14:33:05 -05001421def register_passwords(*args):
Michael Walsh82acf002017-05-04 14:33:05 -05001422 r"""
1423 Register one or more passwords which are to be hidden in output produced
1424 by the print functions in this module.
1425
1426 Note: Blank password values are NOT registered. They are simply ignored.
1427
1428 Description of argument(s):
1429 args One or more password values. If a given
1430 password value is already registered, this
1431 function will simply do nothing.
1432 """
1433
1434 global hidden_text
1435 global password_regex
1436
1437 for password in args:
1438 if password == "":
1439 break
1440 if password in hidden_text:
1441 break
1442
1443 # Place the password into the hidden_text list.
1444 hidden_text.append(password)
1445 # Create a corresponding password regular expression. Escape regex
1446 # special characters too.
1447 password_regex = '(' +\
1448 '|'.join([re.escape(x) for x in hidden_text]) + ')'
1449
Michael Walsh82acf002017-05-04 14:33:05 -05001450
Michael Walsh82acf002017-05-04 14:33:05 -05001451def replace_passwords(buffer):
Michael Walsh82acf002017-05-04 14:33:05 -05001452 r"""
1453 Return the buffer but with all registered passwords replaced by a string
1454 of asterisks.
1455
1456
1457 Description of argument(s):
1458 buffer The string to be returned but with
1459 passwords replaced.
1460 """
1461
1462 global password_regex
1463
1464 if int(os.environ.get("DEBUG_SHOW_PASSWORDS", "0")):
1465 return buffer
1466
1467 if password_regex == "":
1468 # No passwords to replace.
1469 return buffer
1470
1471 return re.sub(password_regex, "********", buffer)
1472
Michael Walshfd2733c2017-11-13 11:36:20 -06001473
1474def create_print_wrapper_funcs(func_names,
1475 stderr_func_names,
1476 replace_dict):
Michael Walshfd2733c2017-11-13 11:36:20 -06001477 r"""
1478 Generate code for print wrapper functions and return the generated code as
1479 a string.
1480
1481 To illustrate, suppose there is a "print_foo_bar" function in the
1482 func_names list.
1483 This function will...
1484 - Expect that there is an sprint_foo_bar function already in existence.
1485 - Create a print_foo_bar function which calls sprint_foo_bar and prints
1486 the result.
1487 - Create a qprint_foo_bar function which calls upon sprint_foo_bar only if
1488 global value quiet is 0.
1489 - Create a dprint_foo_bar function which calls upon sprint_foo_bar only if
1490 global value debug is 1.
1491
1492 Also, code will be generated to define aliases for each function as well.
1493 Each alias will be created by replacing "print_" in the function name with
1494 "p" For example, the alias for print_foo_bar will be pfoo_bar.
1495
1496 Description of argument(s):
1497 func_names A list of functions for which print
1498 wrapper function code is to be generated.
1499 stderr_func_names A list of functions whose generated code
1500 should print to stderr rather than to
1501 stdout.
1502 replace_dict Please see the create_func_def_string
1503 function in wrap_utils.py for details on
1504 this parameter. This parameter will be
1505 passed directly to create_func_def_string.
1506 """
1507
1508 buffer = ""
1509
1510 for func_name in func_names:
1511 if func_name in stderr_func_names:
1512 replace_dict['output_stream'] = "stderr"
1513 else:
1514 replace_dict['output_stream'] = "stdout"
1515
1516 s_func_name = "s" + func_name
1517 q_func_name = "q" + func_name
1518 d_func_name = "d" + func_name
1519
1520 # We don't want to try to redefine the "print" function, thus the
1521 # following if statement.
1522 if func_name != "print":
1523 func_def = create_func_def_string(s_func_name, func_name,
1524 print_func_template,
1525 replace_dict)
1526 buffer += func_def
1527
1528 func_def = create_func_def_string(s_func_name, "q" + func_name,
1529 qprint_func_template, replace_dict)
1530 buffer += func_def
1531
1532 func_def = create_func_def_string(s_func_name, "d" + func_name,
1533 dprint_func_template, replace_dict)
1534 buffer += func_def
1535
Michael Walsh168eb0f2017-12-01 15:35:32 -06001536 func_def = create_func_def_string(s_func_name, "l" + func_name,
1537 lprint_func_template, replace_dict)
1538 buffer += func_def
1539
Michael Walshfd2733c2017-11-13 11:36:20 -06001540 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var).
1541 alias = re.sub("print_", "p", func_name)
1542 alias = re.sub("print", "p", alias)
Michael Walsh168eb0f2017-12-01 15:35:32 -06001543 prefixes = ["", "s", "q", "d", "l"]
Michael Walshfd2733c2017-11-13 11:36:20 -06001544 for prefix in prefixes:
1545 if alias == "p":
1546 continue
1547 func_def = prefix + alias + " = " + prefix + func_name
1548 buffer += func_def + "\n"
1549
1550 return buffer
Michael Walsh82acf002017-05-04 14:33:05 -05001551
1552
Michael Walshde791732016-09-06 14:25:24 -05001553# In the following section of code, we will dynamically create print versions
1554# for each of the sprint functions defined above. So, for example, where we
1555# have an sprint_time() function defined above that returns the time to the
Michael Walsh7423c012016-10-04 10:27:21 -05001556# caller in a string, we will create a corresponding print_time() function
1557# that will print that string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -05001558
Michael Walshfd2733c2017-11-13 11:36:20 -06001559# It can be complicated to follow what's being created by below. Here is an
1560# example of the print_time() function that will be created:
Michael Walshde791732016-09-06 14:25:24 -05001561
Michael Walshfd2733c2017-11-13 11:36:20 -06001562# def print_time(buffer=''):
1563# sys.stdout.write(replace_passwords(sprint_time(buffer=buffer)))
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001564# sys.stdout.flush()
Michael Walshde791732016-09-06 14:25:24 -05001565
Michael Walshfd2733c2017-11-13 11:36:20 -06001566# Templates for the various print wrapper functions.
1567print_func_template = \
1568 [
Michael Walsh81c02342018-01-05 15:43:28 -06001569 " <mod_qualifier>gp_print(<mod_qualifier>replace_passwords(" +
1570 "<call_line>), stream='<output_stream>')"
Michael Walshfd2733c2017-11-13 11:36:20 -06001571 ]
1572
1573qprint_func_template = \
1574 [
Michael Walsh81c02342018-01-05 15:43:28 -06001575 " if int(<mod_qualifier>get_var_value(None, 0, \"quiet\")): return"
Michael Walshfd2733c2017-11-13 11:36:20 -06001576 ] + print_func_template
1577
1578dprint_func_template = \
1579 [
Michael Walsh81c02342018-01-05 15:43:28 -06001580 " if not int(<mod_qualifier>get_var_value(None, 0, \"debug\")):" +
Michael Walshfd2733c2017-11-13 11:36:20 -06001581 " return"
1582 ] + print_func_template
1583
Michael Walsh168eb0f2017-12-01 15:35:32 -06001584lprint_func_template = \
1585 [
Michael Walsh81c02342018-01-05 15:43:28 -06001586 " gp_log(<mod_qualifier>replace_passwords(<call_line>))"
Michael Walsh168eb0f2017-12-01 15:35:32 -06001587 ]
1588
Michael Walsh81c02342018-01-05 15:43:28 -06001589replace_dict = {'output_stream': 'stdout', 'mod_qualifier': ''}
Michael Walshfd2733c2017-11-13 11:36:20 -06001590
1591
1592gp_debug_print("robot_env: " + str(robot_env))
Michael Walshde791732016-09-06 14:25:24 -05001593
1594# func_names contains a list of all print functions which should be created
1595# from their sprint counterparts.
1596func_names = ['print_time', 'print_timen', 'print_error', 'print_varx',
Michael Walsh18176322016-11-15 15:11:21 -06001597 'print_var', 'print_vars', 'print_dashes', 'indent',
1598 'print_call_stack', 'print_func_name', 'print_executing',
1599 'print_pgm_header', 'print_issuing', 'print_pgm_footer',
1600 'print_error_report', 'print', 'printn']
Michael Walshde791732016-09-06 14:25:24 -05001601
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001602# stderr_func_names is a list of functions whose output should go to stderr
1603# rather than stdout.
1604stderr_func_names = ['print_error', 'print_error_report']
Michael Walshde791732016-09-06 14:25:24 -05001605
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001606
Michael Walshfd2733c2017-11-13 11:36:20 -06001607func_defs = create_print_wrapper_funcs(func_names, stderr_func_names,
1608 replace_dict)
1609gp_debug_print(func_defs)
1610exec(func_defs)