blob: f0bc76ddcbd6d3859c2fe2d952e9e5582f4dbc5b [file] [log] [blame]
Michael Walshde791732016-09-06 14:25:24 -05001#!/usr/bin/env python
2
3r"""
Michael Walsh4dbb6002019-05-17 15:51:15 -05004This module provides many print functions such as sprint_var, sprint_time,
5sprint_error, sprint_call_stack.
Michael Walshde791732016-09-06 14:25:24 -05006"""
7
8import sys
9import os
10import time
11import inspect
12import re
13import grp
14import socket
15import argparse
Michael Walsh4dbb6002019-05-17 15:51:15 -050016import copy
George Keishing3b7115a2018-08-02 10:48:17 -050017try:
18 import __builtin__
19except ImportError:
20 import builtins as __builtin__
Michael Walsh7423c012016-10-04 10:27:21 -050021import logging
Michael Walshbec416d2016-11-10 08:54:52 -060022import collections
Michael Walshfd2733c2017-11-13 11:36:20 -060023from wrap_utils import *
Michael Walshbec416d2016-11-10 08:54:52 -060024
Michael Walshbec416d2016-11-10 08:54:52 -060025try:
Michael Walsh2ee77cd2017-03-08 11:50:17 -060026 robot_env = 1
Michael Walshbec416d2016-11-10 08:54:52 -060027 from robot.utils import DotDict
Michael Walsh8e6deb42017-01-27 14:22:41 -060028 from robot.utils import NormalizedDict
Michael Walsh2ee77cd2017-03-08 11:50:17 -060029 from robot.libraries.BuiltIn import BuiltIn
Michael Walshb1500152017-04-12 15:42:43 -050030 # 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}", "")
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050034 except BaseException:
Michael Walshb1500152017-04-12 15:42:43 -050035 robot_env = 0
Michael Walshbec416d2016-11-10 08:54:52 -060036except ImportError:
Michael Walsh2ee77cd2017-03-08 11:50:17 -060037 robot_env = 0
Michael Walsh7423c012016-10-04 10:27:21 -050038
39import gen_arg as ga
Michael Walshde791732016-09-06 14:25:24 -050040
41# Setting these variables for use both inside this module and by programs
42# importing this module.
Michael Walshbf605652017-09-01 12:33:26 -050043pgm_file_path = sys.argv[0]
44pgm_name = os.path.basename(pgm_file_path)
Michael Walsh3ba8ecd2018-04-24 11:33:25 -050045pgm_dir_path = os.path.normpath(re.sub("/" + pgm_name, "", pgm_file_path)) +\
46 os.path.sep
Michael Walsh7423c012016-10-04 10:27:21 -050047
Michael Walshde791732016-09-06 14:25:24 -050048
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.
Michael Walsh4dbb6002019-05-17 15:51:15 -050055dft_indent = 0
Michael Walshde791732016-09-06 14:25:24 -050056
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.
Michael Walsh4dbb6002019-05-17 15:51:15 -050060dft_col1_width = 29
Michael Walshb1500152017-04-12 15:42:43 -050061
62NANOSECONDS = os.environ.get('NANOSECONDS', '1')
63
Michael Walshde791732016-09-06 14:25:24 -050064if NANOSECONDS == "1":
Michael Walsh4dbb6002019-05-17 15:51:15 -050065 dft_col1_width = dft_col1_width + 7
Michael Walshde791732016-09-06 14:25:24 -050066
Michael Walshb1500152017-04-12 15:42:43 -050067SHOW_ELAPSED_TIME = os.environ.get('SHOW_ELAPSED_TIME', '1')
Michael Walshde791732016-09-06 14:25:24 -050068
69if SHOW_ELAPSED_TIME == "1":
70 if NANOSECONDS == "1":
Michael Walsh4dbb6002019-05-17 15:51:15 -050071 dft_col1_width = dft_col1_width + 14
Michael Walshde791732016-09-06 14:25:24 -050072 else:
Michael Walsh4dbb6002019-05-17 15:51:15 -050073 dft_col1_width = dft_col1_width + 7
Michael Walshde791732016-09-06 14:25:24 -050074
75# Initialize some time variables used in module functions.
76start_time = time.time()
Michael Walsh4fea2cf2018-08-22 17:48:18 -050077# sprint_time_last_seconds is used to calculate elapsed seconds.
Michael Walsh61c12982019-03-28 12:38:01 -050078sprint_time_last_seconds = [start_time, start_time]
Michael Walsh4fea2cf2018-08-22 17:48:18 -050079# Define global index for the sprint_time_last_seconds list.
80last_seconds_ix = 0
81
82
Michael Walsh61c12982019-03-28 12:38:01 -050083def 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
Michael Walsh4fea2cf2018-08-22 17:48:18 -050095# 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].
Michael Walsh61c12982019-03-28 12:38:01 -0500102def 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
Michael Walsh4fea2cf2018-08-22 17:48:18 -0500109def lprint_last_seconds_ix():
110 r"""
111 Return lprint last_seconds index value to the caller.
112 """
113 return 1
114
Michael Walshde791732016-09-06 14:25:24 -0500115
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600116# 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))
Michael Walsh7423c012016-10-04 10:27:21 -0500119
Michael Walshde791732016-09-06 14:25:24 -0500120
Michael Walshde791732016-09-06 14:25:24 -0500121def sprint_func_name(stack_frame_ix=None):
Michael Walshde791732016-09-06 14:25:24 -0500122 r"""
123 Return the function name associated with the indicated stack frame.
124
Michael Walsh4dbb6002019-05-17 15:51:15 -0500125 Description of argument(s):
Michael Walshde791732016-09-06 14:25:24 -0500126 stack_frame_ix The index of the stack frame whose
127 function name should be returned. If the
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600128 caller does not specify a value, this
Michael Walshde791732016-09-06 14:25:24 -0500129 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
Michael Walshde791732016-09-06 14:25:24 -0500150
Michael Walsh6f0362c2019-03-25 14:05:14 -0500151def 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500156 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().
Michael Walsh6f0362c2019-03-25 14:05:14 -0500159
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
Michael Walsh1173a522018-05-21 17:24:51 -0500169def 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500177# 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.
Michael Walshde791732016-09-06 14:25:24 -0500179def get_arg_name(var,
180 arg_num=1,
181 stack_frame_ix=1):
Michael Walshde791732016-09-06 14:25:24 -0500182 r"""
183 Return the "name" of an argument passed to a function. This could be a
184 literal or a variable name.
185
Michael Walsh4dbb6002019-05-17 15:51:15 -0500186 Description of argument(s):
187 var The variable whose name is to be returned.
Michael Walsh1173a522018-05-21 17:24:51 -0500188 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.
Michael Walshde791732016-09-06 14:25:24 -0500218 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.
Michael Walsh4dbb6002019-05-17 15:51:15 -0500235 # 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.
Michael Walshde791732016-09-06 14:25:24 -0500238 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500252 # Note: To avoid infinite recursion, avoid calling any function that
253 # calls this function (e.g. sprint_var, valid_value, etc.).
Michael Walshde791732016-09-06 14:25:24 -0500254
Michael Walsh23e7f492017-01-10 11:34:47 -0600255 # 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))
Michael Walshde791732016-09-06 14:25:24 -0500263
Michael Walshde791732016-09-06 14:25:24 -0500264 if stack_frame_ix < 1:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500265 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")
Michael Walshde791732016-09-06 14:25:24 -0500269 return
270
271 if local_debug:
272 debug_indent = 2
Michael Walsh23e7f492017-01-10 11:34:47 -0600273 print("")
274 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500275 print(sprint_func_name() + "() parms:")
Michael Walsh4dbb6002019-05-17 15:51:15 -0500276 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)
Michael Walsh23e7f492017-01-10 11:34:47 -0600279 print("")
280 print_call_stack(debug_indent, 2)
Michael Walshde791732016-09-06 14:25:24 -0500281
Michael Walsh6f0362c2019-03-25 14:05:14 -0500282 work_around_inspect_stack_cwd_failure()
Michael Walsh23e7f492017-01-10 11:34:47 -0600283 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:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500288 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")
Michael Walsh23e7f492017-01-10 11:34:47 -0600294 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...")
Michael Walsh4dbb6002019-05-17 15:51:15 -0500304 print_varx("stack_frame_ix", stack_frame_ix, indent=debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500305
Michael Walsh1173a522018-05-21 17:24:51 -0500306 real_called_func_name = sprint_func_name(stack_frame_ix)
Michael Walsh23e7f492017-01-10 11:34:47 -0600307
308 module = inspect.getmodule(frame)
309
Michael Walsh4dbb6002019-05-17 15:51:15 -0500310 # Though one would expect inspect.getsourcelines(frame) to get all module
Michael Walsh23e7f492017-01-10 11:34:47 -0600311 # source lines if the frame is "<module>", it doesn't do that. Therefore,
Michael Walsh4dbb6002019-05-17 15:51:15 -0500312 # for this special case, do inspect.getsourcelines(module).
Michael Walsh23e7f492017-01-10 11:34:47 -0600313 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:")
Michael Walsh4dbb6002019-05-17 15:51:15 -0500324 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)
Michael Walsh23e7f492017-01-10 11:34:47 -0600332 if local_debug_show_source:
Michael Walsh4dbb6002019-05-17 15:51:15 -0500333 print_varx("source_lines", source_lines, indent=debug_indent)
334 print_varx("real_called_func_name", real_called_func_name,
335 indent=debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600336
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:
Michael Walsh1173a522018-05-21 17:24:51 -0500347 if func_name == real_called_func_name:
Michael Walsh23e7f492017-01-10 11:34:47 -0600348 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.
Michael Walsh1173a522018-05-21 17:24:51 -0500354 aliases = set([real_called_func_name])
Michael Walsh23e7f492017-01-10 11:34:47 -0600355 for func_name, function in all_functions:
Michael Walsh1173a522018-05-21 17:24:51 -0500356 if func_name == real_called_func_name:
Michael Walsh23e7f492017-01-10 11:34:47 -0600357 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.
Michael Walsh1173a522018-05-21 17:24:51 -0500367 aliases.add(re.sub("print_var", "pvar", real_called_func_name))
Michael Walsh23e7f492017-01-10 11:34:47 -0600368
Michael Walsh3f248272018-06-01 13:59:35 -0500369 # The call to the function could be encased in a recast (e.g.
370 # int(func_name())).
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500371 recast_regex = "([^ ]+\\([ ]*)?"
372 import_name_regex = "([a-zA-Z0-9_]+\\.)?"
Michael Walsh3f248272018-06-01 13:59:35 -0500373 func_name_regex = recast_regex + import_name_regex + "(" +\
374 '|'.join(aliases) + ")"
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500375 pre_args_regex = ".*" + func_name_regex + "[ ]*\\("
Michael Walsh23e7f492017-01-10 11:34:47 -0600376
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
Michael Walsh1173a522018-05-21 17:24:51 -0500384 if re.match(pre_args_regex, source_lines[start_line_ix]):
Michael Walsh23e7f492017-01-10 11:34:47 -0600385 found = True
386 break
387 if not found:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500388 print_error("Programmer error - Could not find the source line with"
389 + " a reference to function \"" + real_called_func_name
390 + "\".\n")
Michael Walsh23e7f492017-01-10 11:34:47 -0600391 return
392
Michael Walsh82acf002017-05-04 14:33:05 -0500393 # 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.
Michael Walsh1173a522018-05-21 17:24:51 -0500396 start_indent = get_line_indent(source_lines[start_line_ix])
Michael Walsh37cd29d2018-05-24 13:19:18 -0500397 end_line_ix = line_ix
Michael Walsh23e7f492017-01-10 11:34:47 -0600398 for end_line_ix in range(line_ix + 1, len(source_lines)):
399 if source_lines[end_line_ix].strip() == "":
400 continue
Michael Walsh1173a522018-05-21 17:24:51 -0500401 line_indent = get_line_indent(source_lines[end_line_ix])
Michael Walsh82acf002017-05-04 14:33:05 -0500402 if line_indent <= start_indent:
Michael Walsh23e7f492017-01-10 11:34:47 -0600403 end_line_ix -= 1
404 break
Michael Walsh1173a522018-05-21 17:24:51 -0500405 if start_line_ix != 0:
406 # Check to see whether the start line is a continuation of the prior
Michael Walsha52e9eb2018-09-10 13:56:01 -0500407 # 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:
Michael Walsh1173a522018-05-21 17:24:51 -0500413 start_line_ix -= 1
Michael Walsha52e9eb2018-09-10 13:56:01 -0500414 # Remove the backslash (continuation char) from prior line.
415 source_lines[start_line_ix] = prior_line_stripped
Michael Walsh23e7f492017-01-10 11:34:47 -0600416
417 # Join the start line through the end line into a composite line.
418 composite_line = ''.join(map(str.strip,
Gunnar Mills096cd562018-03-26 10:19:12 -0500419 source_lines[start_line_ix:end_line_ix + 1]))
Michael Walsh1173a522018-05-21 17:24:51 -0500420 # Insert one space after first "=" if there isn't one already.
421 composite_line = re.sub("=[ ]*([^ ])", "= \\1", composite_line, 1)
Michael Walsh7423c012016-10-04 10:27:21 -0500422
Michael Walsh3f248272018-06-01 13:59:35 -0500423 lvalue_regex = "[ ]*=[ ]+" + func_name_regex + ".*"
Michael Walsh1173a522018-05-21 17:24:51 -0500424 lvalue_string = re.sub(lvalue_regex, "", composite_line)
Michael Walsh3f248272018-06-01 13:59:35 -0500425 if lvalue_string == composite_line:
426 # i.e. the regex did not match so there are no lvalues.
427 lvalue_string = ""
Michael Walsh37762f92018-08-07 14:59:18 -0500428 lvalues_list = list(filter(None, map(str.strip, lvalue_string.split(","))))
Michael Walsh3f248272018-06-01 13:59:35 -0500429 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 = {}
Michael Walsh1173a522018-05-21 17:24:51 -0500434 ix = len(lvalues_list) * -1
435 for lvalue in lvalues_list:
436 lvalues[ix] = lvalue
437 ix += 1
Michael Walsh3f248272018-06-01 13:59:35 -0500438 lvalue_prefix_regex = "(.*=[ ]+)?"
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500439 called_func_name_regex = lvalue_prefix_regex + func_name_regex +\
440 "[ ]*\\(.*"
Michael Walsh3f248272018-06-01 13:59:35 -0500441 called_func_name = re.sub(called_func_name_regex, "\\4", composite_line)
Michael Walsh1173a522018-05-21 17:24:51 -0500442 arg_list_etc = "(" + re.sub(pre_args_regex, "", composite_line)
Michael Walshde791732016-09-06 14:25:24 -0500443 if local_debug:
Michael Walsh4dbb6002019-05-17 15:51:15 -0500444 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)
Michael Walshde791732016-09-06 14:25:24 -0500458
459 # Parse arg list...
460 # Initialize...
461 nest_level = -1
462 arg_ix = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500463 args_list = [""]
Michael Walshde791732016-09-06 14:25:24 -0500464 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
Michael Walsh7423c012016-10-04 10:27:21 -0500477 # argument so we increment arg_ix and initialize a new args_list entry.
Michael Walshde791732016-09-06 14:25:24 -0500478 if char == "," and nest_level == 0:
479 arg_ix += 1
Michael Walsh7423c012016-10-04 10:27:21 -0500480 args_list.append("")
Michael Walshde791732016-09-06 14:25:24 -0500481 continue
482
Michael Walsh7423c012016-10-04 10:27:21 -0500483 # For any other character, we append it it to the current arg list
Michael Walshde791732016-09-06 14:25:24 -0500484 # entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500485 args_list[arg_ix] += char
Michael Walshde791732016-09-06 14:25:24 -0500486
487 # Trim whitespace from each list entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500488 args_list = [arg.strip() for arg in args_list]
Michael Walshde791732016-09-06 14:25:24 -0500489
Michael Walsh1173a522018-05-21 17:24:51 -0500490 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
Michael Walsh2750b442018-05-18 14:49:11 -0500497 else:
Michael Walsh1173a522018-05-21 17:24:51 -0500498 if arg_num > len(args_list):
499 argument = args_list
500 else:
501 argument = args_list[arg_num - 1]
Michael Walshde791732016-09-06 14:25:24 -0500502
503 if local_debug:
Michael Walsh4dbb6002019-05-17 15:51:15 -0500504 print_varx("args_list", args_list, indent=debug_indent)
505 print_varx("argument", argument, indent=debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600506 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500507
508 return argument
509
Michael Walshde791732016-09-06 14:25:24 -0500510
Michael Walshde791732016-09-06 14:25:24 -0500511def sprint_time(buffer=""):
Michael Walshde791732016-09-06 14:25:24 -0500512 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500565 Description of argument(s).
Michael Walshde791732016-09-06 14:25:24 -0500566 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
Michael Walsh4fea2cf2018-08-22 17:48:18 -0500573 global last_seconds_ix
Michael Walshde791732016-09-06 14:25:24 -0500574
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" % \
Michael Walsh4fea2cf2018-08-22 17:48:18 -0500588 sprint_time_last_seconds[last_seconds_ix]
Michael Walshde791732016-09-06 14:25:24 -0500589 elapsed_seconds = eval(math_string)
590 if NANOSECONDS == "1":
591 elapsed_seconds = "%11.6f" % elapsed_seconds
592 else:
593 elapsed_seconds = "%4i" % elapsed_seconds
Michael Walsh4fea2cf2018-08-22 17:48:18 -0500594 sprint_time_last_seconds[last_seconds_ix] = cur_time_seconds
Michael Walshde791732016-09-06 14:25:24 -0500595 time_string = time_string + " - " + elapsed_seconds
596
597 return time_string + " - " + buffer
598
Michael Walshde791732016-09-06 14:25:24 -0500599
Michael Walshde791732016-09-06 14:25:24 -0500600def sprint_timen(buffer=""):
Michael Walshde791732016-09-06 14:25:24 -0500601 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
Michael Walshde791732016-09-06 14:25:24 -0500608
Michael Walshde791732016-09-06 14:25:24 -0500609def sprint_error(buffer=""):
Michael Walshde791732016-09-06 14:25:24 -0500610 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500626 Description of argument(s).
Michael Walshde791732016-09-06 14:25:24 -0500627 buffer This will be appended to the formatted
628 error string.
629 """
630
631 return sprint_time() + "**ERROR** " + buffer
632
Michael Walshde791732016-09-06 14:25:24 -0500633
Michael Walsh3f248272018-06-01 13:59:35 -0500634# 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500665 # 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
Michael Walsh3f248272018-06-01 13:59:35 -0500667 # 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500699 # 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
Michael Walsh3f248272018-06-01 13:59:35 -0500701 # 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
Michael Walsh4dbb6002019-05-17 15:51:15 -0500755# 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
Michael Walsh8646d962019-01-21 14:36:13 -0600772def is_dict(var_value):
773 r"""
Michael Walsh4dbb6002019-05-17 15:51:15 -0500774 Return non-zero if var_value is a type of dictionary and 0 if it is not.
775
776 The specific non-zero value returned will indicate what type of dictionary
777 var_value is (see constant functions above).
778
779 Description of argument(s):
780 var_value The object to be analyzed to determine
781 whether it is a dictionary and if so, what
782 type of dictionary.
Michael Walsh8646d962019-01-21 14:36:13 -0600783 """
784
785 type_is_dict = 0
786 if isinstance(var_value, dict):
Michael Walsh4dbb6002019-05-17 15:51:15 -0500787 type_is_dict = dict_type()
Michael Walsh8646d962019-01-21 14:36:13 -0600788 try:
789 if isinstance(var_value, collections.OrderedDict):
Michael Walsh4dbb6002019-05-17 15:51:15 -0500790 type_is_dict = ordered_dict_type()
Michael Walsh8646d962019-01-21 14:36:13 -0600791 except AttributeError:
792 pass
793 try:
794 if isinstance(var_value, DotDict):
Michael Walsh4dbb6002019-05-17 15:51:15 -0500795 type_is_dict = dot_dict_type()
Michael Walsh8646d962019-01-21 14:36:13 -0600796 except NameError:
797 pass
798 try:
799 if isinstance(var_value, NormalizedDict):
Michael Walsh4dbb6002019-05-17 15:51:15 -0500800 type_is_dict = normalized_dict_type()
Michael Walsh8646d962019-01-21 14:36:13 -0600801 except NameError:
802 pass
803 return type_is_dict
804
805
Michael Walsh4dbb6002019-05-17 15:51:15 -0500806def get_int_types():
807 r"""
808 Return a tuple consisting of the valid integer data types for the system
809 and version of python being run.
810
811 Example:
812 (int, long)
813 """
814
815 try:
816 int_types = (int, long)
817 except NameError:
818 int_types = (int,)
819 return int_types
820
821
822def get_string_types():
823 r"""
824 Return a tuple consisting of the valid string data types for the system
825 and version of python being run.
826
827 Example:
828 (str, unicode)
829 """
830
831 try:
832 string_types = (str, unicode)
833 except NameError:
834 string_types = (bytes, str)
835 return string_types
836
837
838def valid_fmts():
839 r"""
840 Return a list of the valid formats that can be specified for the fmt
841 argument of the sprint_varx function (defined below).
842 """
843
844 return [
845 'hexa',
846 'octal',
847 'binary',
848 'blank',
849 'terse',
850 'quote_keys',
851 'show_type']
852
853
854def create_fmt_definition():
855 r"""
856 Create a string consisting of function-definition code that can be
857 executed to create constant fmt definition functions.
858
859 These functions can be used by callers of sprint_var/sprint_varx to set
860 the fmt argument correctly.
861
862 Likewise, the sprint_varx function will use these generated functions to
863 correctly interpret the fmt argument.
864
865 Example output from this function:
866
867 def hexa():
868 return 0x00000001
869 def octal_fmt():
870 return 0x00000002
871 etc.
872 """
873
874 buffer = ""
875 bits = 0x00000001
876 for fmt_name in valid_fmts():
877 buffer += "def " + fmt_name + "():\n"
878 buffer += " return " + "0x%08x" % bits + "\n"
879 bits = bits << 1
880 return buffer
881
882
883# Dynamically create fmt definitions (for use with the fmt argument of
884# sprint_varx function):
885exec(create_fmt_definition())
886
887
888def list_pop(a_list, index=0, default=None):
889 r"""
890 Pop the list entry indicated by the index and return the entry. If no
891 such entry exists, return default.
892
893 Note that the list passed to this function will be modified.
894
895 Description of argument(s):
896 a_list The list from which an entry is to be
897 popped.
898 index The index indicating which entry is to be
899 popped.
900 default The value to be returned if there is no
901 entry at the given index location.
902 """
903 try:
904 return a_list.pop(index)
905 except IndexError:
906 return default
907
908
909def parse_fmt(fmt):
910 r"""
911 Parse the fmt argument and return a tuple consisting of a format and a
912 child format.
913
914 This function was written for use by the sprint_varx function defined in
915 this module.
916
917 When sprint_varx is processing a multi-level object such as a list or
918 dictionary (which in turn may contain other lists or dictionaries), it
919 will use the fmt value to dictate the print formatting of the current
920 level and the child_fmt value to dictate the print formatting of
921 subordinate levels. Consider the following example:
922
923 python code example:
924
925 ord_dict = \
926 collections.OrderedDict([
927 ('one', 1),
928 ('two', 2),
929 ('sub',
930 collections.OrderedDict([
931 ('three', 3), ('four', 4)]))])
932
933 print_var(ord_dict)
934
935 This would generate the following output:
936
937 ord_dict:
938 ord_dict[one]: 1
939 ord_dict[two]: 2
940 ord_dict[sub]:
941 ord_dict[sub][three]: 3
942 ord_dict[sub][four]: 4
943
944 The first level in this example is the line that simply says "ord_dict".
945 The second level is comprised of the dictionary entries with the keys
946 'one', 'two' and 'sub'. The third level is comprised of the last 2 lines
947 (i.e. printed values 3 and 4).
948
949 Given the data structure shown above, the programmer could code the
950 following where fmt is a simple integer value set by calling the terse()
951 function.
952
953 print_var(ord_dict, fmt=terse())
954
955 The output would look like this:
956
957 ord_dict:
958 [one]: 1
959 [two]: 2
960 [sub]:
961 [three]: 3
962 [four]: 4
963
964 Note the terse format where the name of the object ("ord_dict") is not
965 repeated on every line as it was in example #1.
966
967 If the programmer wishes to get more granular with the fmt argument,
968 he/she can specify it as a list where each entry corresponds to a level of
969 the object being printed. The last such list entry governs the print
970 formatting of all subordinate parts of the given object.
971
972 Look at each of the following code examples and their corresponding
973 output. See how the show_type() formatting affects the printing depending
974 on which position it occupies in the fmt list argument:
975
976 print_var(ord_dict, fmt=[show_type()])
977
978 ord_dict: <collections.OrderedDict>
979 ord_dict[one]: 1 <int>
980 ord_dict[two]: 2 <int>
981 ord_dict[sub]: <collections.OrderedDict>
982 ord_dict[sub][three]: 3 <int>
983 ord_dict[sub][four]: 4 <int>
984
985 print_var(ord_dict, fmt=[0, show_type()])
986
987 ord_dict:
988 ord_dict[one]: 1 <int>
989 ord_dict[two]: 2 <int>
990 ord_dict[sub]: <collections.OrderedDict>
991 ord_dict[sub][three]: 3 <int>
992 ord_dict[sub][four]: 4 <int>
993
994 print_var(ord_dict, fmt=[0, 0, show_type()])
995
996 ord_dict:
997 ord_dict[one]: 1
998 ord_dict[two]: 2
999 ord_dict[sub]:
1000 ord_dict[sub][three]: 3 <int>
1001 ord_dict[sub][four]: 4 <int>
1002
1003 Description of argument(s):
1004 fmt The format argument such as is passed to
1005 sprint_varx. This argument may be an
1006 integer or a list of integers. See the
1007 prolog of sprint_varx for more details.
1008 """
1009
1010 # Make a deep copy of the fmt argument in order to avoid modifying the
1011 # caller's fmt value when it is a list.
1012 fmt = copy.deepcopy(fmt)
1013 try:
1014 # Assume fmt is a list. Pop the first element from the list.
1015 first_element = list_pop(fmt, index=0, default=0)
1016 # Return the first list element along with either 1) the remainder of
1017 # the fmt list if not null or 2) another copy of the first element.
1018 return first_element, fmt if len(fmt) else first_element
1019 except AttributeError:
1020 # fmt is not a list so treat it as a simple integer value.
1021 return fmt, fmt
1022
1023
Michael Walshde791732016-09-06 14:25:24 -05001024def sprint_varx(var_name,
1025 var_value,
Michael Walsh4dbb6002019-05-17 15:51:15 -05001026 fmt=0,
1027 indent=dft_indent,
1028 col1_width=dft_col1_width,
Michael Walshd2869032018-03-22 16:12:11 -05001029 trailing_char="\n",
Michael Walsh4dbb6002019-05-17 15:51:15 -05001030 key_list=None,
1031 delim=":"):
Michael Walshde791732016-09-06 14:25:24 -05001032 r"""
Michael Walsh4dbb6002019-05-17 15:51:15 -05001033 Print the var name/value passed to it. If the caller lets col1_width
Michael Walshde791732016-09-06 14:25:24 -05001034 default, the printing lines up nicely with output generated by the
1035 print_time functions.
1036
1037 Note that the sprint_var function (defined below) can be used to call this
1038 function so that the programmer does not need to pass the var_name.
1039 sprint_var will figure out the var_name. The sprint_var function is the
1040 one that would normally be used by the general user.
1041
1042 For example, the following python code:
1043
1044 first_name = "Mike"
1045 print_time("Doing this...\n")
1046 print_varx("first_name", first_name)
1047 print_time("Doing that...\n")
1048
1049 Will generate output like this:
1050
1051 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this...
1052 first_name: Mike
1053 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that...
1054
1055 This function recognizes several complex types of data such as dict, list
1056 or tuple.
1057
1058 For example, the following python code:
1059
1060 my_dict = dict(one=1, two=2, three=3)
1061 print_var(my_dict)
1062
1063 Will generate the following output:
1064
1065 my_dict:
1066 my_dict[three]: 3
1067 my_dict[two]: 2
1068 my_dict[one]: 1
1069
Michael Walsh4dbb6002019-05-17 15:51:15 -05001070 Description of argument(s).
Michael Walshde791732016-09-06 14:25:24 -05001071 var_name The name of the variable to be printed.
1072 var_value The value of the variable to be printed.
Michael Walsh4dbb6002019-05-17 15:51:15 -05001073 fmt A bit map to dictate the format of the
1074 output. For printing multi-level objects
1075 like lists and dictionaries, this argument
1076 may also be a list of bit maps. The first
1077 list element pertains to the highest level
1078 of output, the second element pertains to
1079 the 2nd level of output, etc. The last
1080 element in the list pertains to all
1081 subordinate levels. The bits can be set
1082 using the dynamically created functionhs
1083 above. Example: sprint_varx("var1", var1,
1084 fmt=terse()). Note that these values can
1085 be OR'ed together: print_var(var1, hexa()
1086 | terse()). If the caller ORs mutually
1087 exclusive bits (hexa() | octal()),
1088 behavior is not guaranteed. The following
1089 features are supported:
1090 hexa Print all integer values in hexadecimal
1091 format.
1092 octal Print all integer values in octal format.
1093 binary Print all integer values in binary format.
1094 blank For blank string values, print "<blank>"
1095 instead of an actual blank.
1096 terse For structured values like dictionaries,
1097 lists, etc. do not repeat the name of the
1098 variable on each line to the right of the
1099 key or subscript value. Example: print
1100 "[key1]" instead of "my_dict[key1]".
1101 quote_keys Quote dictionary keys in the output.
1102 Example: my_dict['key1'] instead of
1103 my_dict[key1].
1104 show_type Show the type of the data in angled
1105 brackets just to the right of the data.
1106 indent The number of spaces to indent the output.
1107 col1_width The width of the output column containing
Michael Walshde791732016-09-06 14:25:24 -05001108 the variable name. The default value of
1109 this is adjusted so that the var_value
1110 lines up with text printed via the
1111 print_time function.
Michael Walsh7423c012016-10-04 10:27:21 -05001112 trailing_char The character to be used at the end of the
1113 returned string. The default value is a
1114 line feed.
Michael Walshd2869032018-03-22 16:12:11 -05001115 key_list A list of which dictionary keys should be
1116 printed. All others keys will be skipped.
1117 Each value in key_list will be regarded
1118 as a regular expression and it will be
1119 regarded as anchored to the beginning and
1120 ends of the dictionary key being
1121 referenced. For example if key_list is
1122 ["one", "two"], the resulting regex used
1123 will be "^one|two$", i.e. only keys "one"
1124 and "two" from the var_value dictionary
1125 will be printed. As another example, if
1126 the caller were to specify a key_list of
1127 ["one.*"], then only dictionary keys whose
1128 names begin with "one" will be printed.
1129 Note: This argument pertains only to
1130 var_values which are dictionaries.
Michael Walsh4dbb6002019-05-17 15:51:15 -05001131 delim The value to be used to delimit the
1132 variable name from the variable value in
1133 the output.
Michael Walsh7423c012016-10-04 10:27:21 -05001134 """
Michael Walshde791732016-09-06 14:25:24 -05001135
Michael Walsh4dbb6002019-05-17 15:51:15 -05001136 fmt, child_fmt = parse_fmt(fmt)
1137
1138 if fmt & show_type():
1139 type_str = "<" + str(type(var_value)).split("'")[1] + ">"
1140 # Compose object type categories.
1141 int_types = get_int_types()
1142 string_types = get_string_types()
1143 simple_types = int_types + string_types + (float, bool, type, type(None))
1144 # Determine the type.
1145 if type(var_value) in simple_types:
Michael Walshde791732016-09-06 14:25:24 -05001146 # The data type is simple in the sense that it has no subordinate
1147 # parts.
Michael Walsh4dbb6002019-05-17 15:51:15 -05001148 # Adjust col1_width.
1149 col1_width = col1_width - indent
1150 # Set default value for value_format.
1151 value_format = "%s"
1152 # Process format requests.
1153 if type(var_value) in int_types:
1154 # Process format values pertaining to int types.
1155 if fmt & hexa():
Michael Walsh3f248272018-06-01 13:59:35 -05001156 num_hex_digits = max(dft_num_hex_digits(),
1157 get_req_num_hex_digits(var_value))
1158 # Convert a negative number to its positive twos complement
1159 # for proper printing. For example, instead of printing -1 as
1160 # "0x-000000000000001" it will be printed as
1161 # "0xffffffffffffffff".
1162 var_value = var_value & (2 ** (num_hex_digits * 4) - 1)
1163 value_format = "0x%0" + str(num_hex_digits) + "x"
Michael Walsh4dbb6002019-05-17 15:51:15 -05001164 elif fmt & octal():
1165 value_format = "0o%016o"
1166 elif fmt & binary():
1167 num_digits, remainder = \
1168 divmod(max(bit_length(var_value), 1), 8)
1169 num_digits *= 8
1170 if remainder:
1171 num_digits += 8
1172 num_digits += 2
1173 value_format = '#0' + str(num_digits) + 'b'
1174 var_value = format(var_value, value_format)
1175 value_format = "%s"
1176 elif type(var_value) in string_types:
1177 # Process format values pertaining to string types.
1178 if fmt & blank() and var_value == "":
1179 value_format = "%s"
1180 var_value = "<blank>"
1181 elif type(var_value) is type:
1182 var_value = str(var_value).split("'")[1]
1183 format_string = "%" + str(indent) + "s%-" + str(col1_width) + "s" \
1184 + value_format
1185 if fmt & show_type():
1186 if var_value != "":
1187 format_string += " "
1188 format_string += type_str
1189 format_string += trailing_char
1190 if fmt & terse():
1191 # Strip everything leading up to the first left square brace.
1192 var_name = re.sub(r".*\[", "[", var_name)
Michael Walsh3383e652017-09-01 17:10:59 -05001193 if value_format == "0x%08x":
Michael Walsh4dbb6002019-05-17 15:51:15 -05001194 return format_string % ("", str(var_name) + delim,
Michael Walsh3383e652017-09-01 17:10:59 -05001195 var_value & 0xffffffff)
1196 else:
Michael Walsh4dbb6002019-05-17 15:51:15 -05001197 return format_string % ("", str(var_name) + delim, var_value)
Michael Walshde791732016-09-06 14:25:24 -05001198 else:
1199 # The data type is complex in the sense that it has subordinate parts.
Michael Walsh4dbb6002019-05-17 15:51:15 -05001200 if fmt & terse():
1201 # Strip everything leading up to the first square brace.
1202 loc_var_name = re.sub(r".*\[", "[", var_name)
1203 else:
1204 loc_var_name = var_name
1205 format_string = "%" + str(indent) + "s%s\n"
1206 buffer = format_string % ("", loc_var_name + ":")
1207 if fmt & show_type():
1208 buffer = buffer.replace("\n", " " + type_str + "\n")
1209 indent += 2
Michael Walsh7423c012016-10-04 10:27:21 -05001210 try:
1211 length = len(var_value)
1212 except TypeError:
Michael Walsh23e7f492017-01-10 11:34:47 -06001213 length = 0
Michael Walsh7423c012016-10-04 10:27:21 -05001214 ix = 0
1215 loc_trailing_char = "\n"
Michael Walsh8646d962019-01-21 14:36:13 -06001216 if is_dict(var_value):
Michael Walsh4dbb6002019-05-17 15:51:15 -05001217 if type(child_fmt) is list:
1218 child_quote_keys = (child_fmt[0] & quote_keys())
1219 else:
1220 child_quote_keys = (child_fmt & quote_keys())
Michael Walsh37762f92018-08-07 14:59:18 -05001221 for key, value in var_value.items():
Michael Walshd2869032018-03-22 16:12:11 -05001222 if key_list is not None:
1223 key_list_regex = "^" + "|".join(key_list) + "$"
1224 if not re.match(key_list_regex, key):
1225 continue
Michael Walsh7423c012016-10-04 10:27:21 -05001226 ix += 1
1227 if ix == length:
1228 loc_trailing_char = trailing_char
Michael Walsh4dbb6002019-05-17 15:51:15 -05001229 if child_quote_keys:
1230 key = "'" + key + "'"
1231 key = "[" + str(key) + "]"
1232 buffer += sprint_varx(var_name + key, value, child_fmt, indent,
1233 col1_width, loc_trailing_char, key_list)
Michael Walsh7423c012016-10-04 10:27:21 -05001234 elif type(var_value) in (list, tuple, set):
Michael Walshde791732016-09-06 14:25:24 -05001235 for key, value in enumerate(var_value):
Michael Walsh7423c012016-10-04 10:27:21 -05001236 ix += 1
1237 if ix == length:
1238 loc_trailing_char = trailing_char
Michael Walsh4dbb6002019-05-17 15:51:15 -05001239 key = "[" + str(key) + "]"
1240 buffer += sprint_varx(var_name + key, value, child_fmt, indent,
1241 col1_width, loc_trailing_char, key_list)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001242 elif isinstance(var_value, argparse.Namespace):
Michael Walshde791732016-09-06 14:25:24 -05001243 for key in var_value.__dict__:
Michael Walsh7423c012016-10-04 10:27:21 -05001244 ix += 1
1245 if ix == length:
1246 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -05001247 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \
Michael Walsh4dbb6002019-05-17 15:51:15 -05001248 + ", var_value." + key + ", child_fmt, indent," \
1249 + " col1_width, loc_trailing_char, key_list)"
Michael Walshde791732016-09-06 14:25:24 -05001250 exec(cmd_buf)
1251 else:
1252 var_type = type(var_value).__name__
1253 func_name = sys._getframe().f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -05001254 var_value = "<" + var_type + " type not supported by " + \
1255 func_name + "()>"
Michael Walshde791732016-09-06 14:25:24 -05001256 value_format = "%s"
Michael Walsh4dbb6002019-05-17 15:51:15 -05001257 indent -= 2
1258 # Adjust col1_width.
1259 col1_width = col1_width - indent
1260 format_string = "%" + str(indent) + "s%-" \
1261 + str(col1_width) + "s" + value_format + trailing_char
Michael Walsh0f2ea5f2017-02-20 15:55:00 -06001262 return format_string % ("", str(var_name) + ":", var_value)
Michael Walsh23e7f492017-01-10 11:34:47 -06001263
Michael Walshde791732016-09-06 14:25:24 -05001264 return buffer
1265
1266 return ""
1267
Michael Walshde791732016-09-06 14:25:24 -05001268
Michael Walsh4dbb6002019-05-17 15:51:15 -05001269def sprint_var(*args, **kwargs):
Michael Walshde791732016-09-06 14:25:24 -05001270 r"""
Michael Walsh4dbb6002019-05-17 15:51:15 -05001271 Figure out the name of the first argument for the caller and then call
Michael Walshde791732016-09-06 14:25:24 -05001272 sprint_varx with it. Therefore, the following 2 calls are equivalent:
1273 sprint_varx("var1", var1)
1274 sprint_var(var1)
Michael Walsh4dbb6002019-05-17 15:51:15 -05001275
1276 See sprint_varx for description of arguments.
Michael Walshde791732016-09-06 14:25:24 -05001277 """
1278
Michael Walshde791732016-09-06 14:25:24 -05001279 stack_frame = 2
Michael Walsh7423c012016-10-04 10:27:21 -05001280 caller_func_name = sprint_func_name(2)
1281 if caller_func_name.endswith("print_var"):
Michael Walshde791732016-09-06 14:25:24 -05001282 stack_frame += 1
Michael Walsh4dbb6002019-05-17 15:51:15 -05001283 # Get the name of the first variable passed to this function.
Michael Walshde791732016-09-06 14:25:24 -05001284 var_name = get_arg_name(None, 1, stack_frame)
Michael Walsh4dbb6002019-05-17 15:51:15 -05001285 return sprint_varx(var_name, *args, **kwargs)
Michael Walshde791732016-09-06 14:25:24 -05001286
1287
Michael Walsh4dbb6002019-05-17 15:51:15 -05001288def sprint_vars(*args, **kwargs):
Michael Walsh18176322016-11-15 15:11:21 -06001289 r"""
1290 Sprint the values of one or more variables.
1291
Michael Walsh4dbb6002019-05-17 15:51:15 -05001292 Description of argument(s):
1293 args The variable values which are to be
1294 printed.
1295 kwargs See sprint_varx (above) for description of
1296 additional arguments.
Michael Walsh18176322016-11-15 15:11:21 -06001297 """
1298
Michael Walsh18176322016-11-15 15:11:21 -06001299 stack_frame = 2
1300 caller_func_name = sprint_func_name(2)
1301 if caller_func_name.endswith("print_vars"):
1302 stack_frame += 1
1303
Michael Walsh18176322016-11-15 15:11:21 -06001304 buffer = ""
Michael Walsh4dbb6002019-05-17 15:51:15 -05001305 arg_num = 1
1306 for var_value in args:
1307 var_name = get_arg_name(None, arg_num, stack_frame)
1308 buffer += sprint_varx(var_name, var_value, **kwargs)
1309 arg_num += 1
Michael Walsh18176322016-11-15 15:11:21 -06001310
1311 return buffer
1312
Michael Walsh18176322016-11-15 15:11:21 -06001313
Michael Walsh4dbb6002019-05-17 15:51:15 -05001314def sprint_dashes(indent=dft_indent,
Michael Walsh7423c012016-10-04 10:27:21 -05001315 width=80,
1316 line_feed=1,
1317 char="-"):
Michael Walshde791732016-09-06 14:25:24 -05001318 r"""
1319 Return a string of dashes to the caller.
1320
Michael Walsh4dbb6002019-05-17 15:51:15 -05001321 Description of argument(s):
Michael Walshde791732016-09-06 14:25:24 -05001322 indent The number of characters to indent the
1323 output.
1324 width The width of the string of dashes.
1325 line_feed Indicates whether the output should end
1326 with a line feed.
Michael Walsh7423c012016-10-04 10:27:21 -05001327 char The character to be repeated in the output
1328 string.
Michael Walshde791732016-09-06 14:25:24 -05001329 """
1330
Michael Walsh7423c012016-10-04 10:27:21 -05001331 width = int(width)
Michael Walsh23e7f492017-01-10 11:34:47 -06001332 buffer = " " * int(indent) + char * width
Michael Walshde791732016-09-06 14:25:24 -05001333 if line_feed:
1334 buffer += "\n"
1335
1336 return buffer
1337
Michael Walshde791732016-09-06 14:25:24 -05001338
Michael Walsh7423c012016-10-04 10:27:21 -05001339def sindent(text="",
1340 indent=0):
Michael Walsh7423c012016-10-04 10:27:21 -05001341 r"""
1342 Pre-pend the specified number of characters to the text string (i.e.
1343 indent it) and return it.
1344
Michael Walsh4dbb6002019-05-17 15:51:15 -05001345 Description of argument(s):
Michael Walsh7423c012016-10-04 10:27:21 -05001346 text The string to be indented.
1347 indent The number of characters to indent the
1348 string.
1349 """
1350
1351 format_string = "%" + str(indent) + "s%s"
1352 buffer = format_string % ("", text)
1353
1354 return buffer
1355
Michael Walsh7423c012016-10-04 10:27:21 -05001356
Michael Walsh662e13b2019-03-01 15:54:08 -06001357func_line_style_std = None
1358func_line_style_short = 1
1359
1360
1361def sprint_func_line(stack_frame, style=None):
Michael Walsh47aa2a42018-12-10 15:06:02 -06001362 r"""
1363 For the given stack_frame, return a formatted string containing the
1364 function name and all its arguments.
1365
1366 Example:
1367
1368 func1(last_name = 'walsh', first_name = 'mikey')
1369
1370 Description of argument(s):
1371 stack_frame A stack frame (such as is returned by
1372 inspect.stack()).
Michael Walsh662e13b2019-03-01 15:54:08 -06001373 style Indicates the style or formatting of the
1374 result string. Acceptable values are
1375 shown above.
1376
1377 Description of styles:
1378 func_line_style_std The standard formatting.
1379 func_line_style_short 1) The self parm (associated with methods)
1380 will be dropped. 2) The args and kwargs
1381 values will be treated as special. In
1382 both cases the arg name ('args' or
1383 'kwargs') will be dropped and only the
1384 values will be shown.
Michael Walsh47aa2a42018-12-10 15:06:02 -06001385 """
1386
1387 func_name = str(stack_frame[3])
1388 if func_name == "?":
1389 # "?" is the name used when code is not in a function.
1390 func_name = "(none)"
1391
1392 if func_name == "<module>":
1393 # If the func_name is the "main" program, we simply get the command
1394 # line call string.
1395 func_and_args = ' '.join(sys.argv)
1396 else:
1397 # Get the program arguments.
1398 (args, varargs, keywords, locals) =\
1399 inspect.getargvalues(stack_frame[0])
1400
1401 args_list = []
1402 for arg_name in filter(None, args + [varargs, keywords]):
1403 # Get the arg value from frame locals.
1404 arg_value = locals[arg_name]
1405 if arg_name == 'self':
Michael Walsh662e13b2019-03-01 15:54:08 -06001406 if style == func_line_style_short:
1407 continue
Michael Walsh47aa2a42018-12-10 15:06:02 -06001408 # Manipulations to improve output for class methods.
1409 func_name = arg_value.__class__.__name__ + "." + func_name
1410 args_list.append(arg_name + " = <self>")
Michael Walsh662e13b2019-03-01 15:54:08 -06001411 elif (style == func_line_style_short
1412 and arg_name == 'args'
1413 and type(arg_value) in (list, tuple)):
1414 if len(arg_value) == 0:
1415 continue
1416 args_list.append(repr(', '.join(arg_value)))
1417 elif (style == func_line_style_short
1418 and arg_name == 'kwargs'
1419 and type(arg_value) is dict):
1420 for key, value in arg_value.items():
1421 args_list.append(key + "=" + repr(value))
Michael Walsh47aa2a42018-12-10 15:06:02 -06001422 else:
1423 args_list.append(arg_name + " = " + repr(arg_value))
1424 args_str = "(" + ', '.join(map(str, args_list)) + ")"
1425
1426 # Now we need to print this in a nicely-wrapped way.
1427 func_and_args = func_name + args_str
1428
1429 return func_and_args
1430
1431
Michael Walsh7423c012016-10-04 10:27:21 -05001432def sprint_call_stack(indent=0,
Michael Walsh662e13b2019-03-01 15:54:08 -06001433 stack_frame_ix=0,
1434 style=None):
Michael Walshde791732016-09-06 14:25:24 -05001435 r"""
1436 Return a call stack report for the given point in the program with line
1437 numbers, function names and function parameters and arguments.
1438
1439 Sample output:
1440
1441 -------------------------------------------------------------------------
1442 Python function call stack
1443
1444 Line # Function name and arguments
1445 ------ ------------------------------------------------------------------
Michael Walsh47aa2a42018-12-10 15:06:02 -06001446 424 sprint_call_stack()
1447 4 print_call_stack()
1448 31 func1(last_name = 'walsh', first_name = 'mikey')
Michael Walshde791732016-09-06 14:25:24 -05001449 59 /tmp/scr5.py
1450 -------------------------------------------------------------------------
1451
Michael Walsh4dbb6002019-05-17 15:51:15 -05001452 Description of argument(s):
Michael Walshde791732016-09-06 14:25:24 -05001453 indent The number of characters to indent each
1454 line of output.
1455 stack_frame_ix The index of the first stack frame which
1456 is to be returned.
Michael Walsh662e13b2019-03-01 15:54:08 -06001457 style See the sprint_line_func prolog above for
1458 details.
Michael Walshde791732016-09-06 14:25:24 -05001459 """
1460
1461 buffer = ""
Michael Walsh7423c012016-10-04 10:27:21 -05001462 buffer += sprint_dashes(indent)
1463 buffer += sindent("Python function call stack\n\n", indent)
1464 buffer += sindent("Line # Function name and arguments\n", indent)
1465 buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73)
Michael Walshde791732016-09-06 14:25:24 -05001466
1467 # Grab the current program stack.
Michael Walsh6f0362c2019-03-25 14:05:14 -05001468 work_around_inspect_stack_cwd_failure()
Michael Walshde791732016-09-06 14:25:24 -05001469 current_stack = inspect.stack()
1470
1471 # Process each frame in turn.
1472 format_string = "%6s %s\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001473 ix = 0
Michael Walshde791732016-09-06 14:25:24 -05001474 for stack_frame in current_stack:
Michael Walsh7423c012016-10-04 10:27:21 -05001475 if ix < stack_frame_ix:
1476 ix += 1
1477 continue
Michael Walsh4dbb6002019-05-17 15:51:15 -05001478 # Make the line number shown to be the line where one finds the line
Michael Walsh23e7f492017-01-10 11:34:47 -06001479 # shown.
1480 try:
1481 line_num = str(current_stack[ix + 1][2])
1482 except IndexError:
1483 line_num = ""
Michael Walsh662e13b2019-03-01 15:54:08 -06001484 func_and_args = sprint_func_line(stack_frame, style=style)
Michael Walshde791732016-09-06 14:25:24 -05001485
Michael Walsh23e7f492017-01-10 11:34:47 -06001486 buffer += sindent(format_string % (line_num, func_and_args), indent)
Michael Walsh7423c012016-10-04 10:27:21 -05001487 ix += 1
Michael Walshde791732016-09-06 14:25:24 -05001488
Michael Walsh7423c012016-10-04 10:27:21 -05001489 buffer += sprint_dashes(indent)
Michael Walshde791732016-09-06 14:25:24 -05001490
1491 return buffer
1492
Michael Walshde791732016-09-06 14:25:24 -05001493
Michael Walsh662e13b2019-03-01 15:54:08 -06001494def sprint_executing(stack_frame_ix=None, style=None):
Michael Walshde791732016-09-06 14:25:24 -05001495 r"""
1496 Print a line indicating what function is executing and with what parameter
1497 values. This is useful for debugging.
1498
1499 Sample output:
1500
Michael Walsh47aa2a42018-12-10 15:06:02 -06001501 #(CDT) 2016/08/25 17:54:27 - Executing: func1(x = 1)
Michael Walshde791732016-09-06 14:25:24 -05001502
Michael Walsh4dbb6002019-05-17 15:51:15 -05001503 Description of argument(s):
Michael Walshde791732016-09-06 14:25:24 -05001504 stack_frame_ix The index of the stack frame whose
1505 function info should be returned. If the
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001506 caller does not specify a value, this
Michael Walshde791732016-09-06 14:25:24 -05001507 function will set the value to 1 which is
1508 the index of the caller's stack frame. If
1509 the caller is the wrapper function
1510 "print_executing", this function will bump
1511 it up by 1.
Michael Walsh662e13b2019-03-01 15:54:08 -06001512 style See the sprint_line_func prolog above for
1513 details.
Michael Walshde791732016-09-06 14:25:24 -05001514 """
1515
1516 # If user wants default stack_frame_ix.
1517 if stack_frame_ix is None:
1518 func_name = sys._getframe().f_code.co_name
1519 caller_func_name = sys._getframe(1).f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -05001520 if caller_func_name.endswith(func_name[1:]):
Michael Walshde791732016-09-06 14:25:24 -05001521 stack_frame_ix = 2
1522 else:
1523 stack_frame_ix = 1
1524
Michael Walsh6f0362c2019-03-25 14:05:14 -05001525 work_around_inspect_stack_cwd_failure()
Michael Walshde791732016-09-06 14:25:24 -05001526 stack_frame = inspect.stack()[stack_frame_ix]
1527
Michael Walsh662e13b2019-03-01 15:54:08 -06001528 func_and_args = sprint_func_line(stack_frame, style)
Michael Walshde791732016-09-06 14:25:24 -05001529
1530 return sprint_time() + "Executing: " + func_and_args + "\n"
1531
Michael Walshde791732016-09-06 14:25:24 -05001532
Michael Walshbec416d2016-11-10 08:54:52 -06001533def sprint_pgm_header(indent=0,
1534 linefeed=1):
Michael Walshde791732016-09-06 14:25:24 -05001535 r"""
1536 Return a standardized header that programs should print at the beginning
1537 of the run. It includes useful information like command line, pid,
1538 userid, program parameters, etc.
1539
Michael Walsh4dbb6002019-05-17 15:51:15 -05001540 Description of argument(s):
Michael Walsh7423c012016-10-04 10:27:21 -05001541 indent The number of characters to indent each
1542 line of output.
Michael Walshbec416d2016-11-10 08:54:52 -06001543 linefeed Indicates whether a line feed be included
1544 at the beginning and end of the report.
Michael Walshde791732016-09-06 14:25:24 -05001545 """
1546
Michael Walsh4dbb6002019-05-17 15:51:15 -05001547 col1_width = dft_col1_width + indent
Michael Walshbec416d2016-11-10 08:54:52 -06001548
1549 buffer = ""
1550 if linefeed:
1551 buffer = "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001552
Michael Walshdb6e68a2017-05-23 17:55:31 -05001553 if robot_env:
1554 suite_name = BuiltIn().get_variable_value("${suite_name}")
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001555 buffer += sindent(sprint_time("Running test suite \"" + suite_name
1556 + "\".\n"), indent)
Michael Walshdb6e68a2017-05-23 17:55:31 -05001557
Michael Walsh7423c012016-10-04 10:27:21 -05001558 buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent)
1559 buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n",
1560 indent)
Michael Walshbec416d2016-11-10 08:54:52 -06001561 buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent,
Michael Walsh4dbb6002019-05-17 15:51:15 -05001562 col1_width)
Michael Walsh7423c012016-10-04 10:27:21 -05001563 # We want the output to show a customized name for the pid and pgid but
1564 # we want it to look like a valid variable name. Therefore, we'll use
Michael Walshde791732016-09-06 14:25:24 -05001565 # pgm_name_var_name which was set when this module was imported.
Michael Walshbec416d2016-11-10 08:54:52 -06001566 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent,
Michael Walsh4dbb6002019-05-17 15:51:15 -05001567 col1_width)
Michael Walshbec416d2016-11-10 08:54:52 -06001568 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent,
Michael Walsh4dbb6002019-05-17 15:51:15 -05001569 col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001570 userid_num = str(os.geteuid())
1571 try:
1572 username = os.getlogin()
1573 except OSError:
1574 if userid_num == "0":
1575 username = "root"
1576 else:
1577 username = "?"
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001578 buffer += sprint_varx("uid", userid_num + " (" + username
Michael Walsh4dbb6002019-05-17 15:51:15 -05001579 + ")", 0, indent, col1_width)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001580 buffer += sprint_varx("gid", str(os.getgid()) + " ("
1581 + str(grp.getgrgid(os.getgid()).gr_name) + ")", 0,
Michael Walsh4dbb6002019-05-17 15:51:15 -05001582 indent, col1_width)
Michael Walshbec416d2016-11-10 08:54:52 -06001583 buffer += sprint_varx("host_name", socket.gethostname(), 0, indent,
Michael Walsh4dbb6002019-05-17 15:51:15 -05001584 col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001585 try:
1586 DISPLAY = os.environ['DISPLAY']
1587 except KeyError:
1588 DISPLAY = ""
Michael Walsh4dbb6002019-05-17 15:51:15 -05001589 buffer += sprint_var(DISPLAY, 0, indent,
1590 col1_width)
1591 # TODO: Add code to print caller's parms.
Michael Walshde791732016-09-06 14:25:24 -05001592
Michael Walsh7423c012016-10-04 10:27:21 -05001593 # __builtin__.arg_obj is created by the get_arg module function,
1594 # gen_get_options.
1595 try:
1596 buffer += ga.sprint_args(__builtin__.arg_obj, indent)
1597 except AttributeError:
1598 pass
1599
Michael Walshdb6e68a2017-05-23 17:55:31 -05001600 if robot_env:
1601 # Get value of global parm_list.
1602 parm_list = BuiltIn().get_variable_value("${parm_list}")
1603
1604 for parm in parm_list:
1605 parm_value = BuiltIn().get_variable_value("${" + parm + "}")
Michael Walsh4dbb6002019-05-17 15:51:15 -05001606 buffer += sprint_varx(parm, parm_value, 0, indent, col1_width)
Michael Walshdb6e68a2017-05-23 17:55:31 -05001607
1608 # Setting global program_pid.
1609 BuiltIn().set_global_variable("${program_pid}", os.getpid())
1610
Michael Walshbec416d2016-11-10 08:54:52 -06001611 if linefeed:
1612 buffer += "\n"
Michael Walshde791732016-09-06 14:25:24 -05001613
1614 return buffer
1615
Michael Walshde791732016-09-06 14:25:24 -05001616
Michael Walsh7423c012016-10-04 10:27:21 -05001617def sprint_error_report(error_text="\n",
Michael Walshdb6e68a2017-05-23 17:55:31 -05001618 indent=2,
1619 format=None):
Michael Walsh7423c012016-10-04 10:27:21 -05001620 r"""
1621 Return a string with a standardized report which includes the caller's
1622 error text, the call stack and the program header.
1623
Michael Walsh4dbb6002019-05-17 15:51:15 -05001624 Description of argument(s):
Michael Walsh7423c012016-10-04 10:27:21 -05001625 error_text The error text to be included in the
1626 report. The caller should include any
1627 needed linefeeds.
1628 indent The number of characters to indent each
1629 line of output.
Michael Walshdb6e68a2017-05-23 17:55:31 -05001630 format Long or short format. Long includes
1631 extras like lines of dashes, call stack,
1632 etc.
Michael Walsh7423c012016-10-04 10:27:21 -05001633 """
1634
Michael Walshdb6e68a2017-05-23 17:55:31 -05001635 # Process input.
1636 indent = int(indent)
1637 if format is None:
1638 if robot_env:
1639 format = 'short'
1640 else:
1641 format = 'long'
1642 error_text = error_text.rstrip('\n') + '\n'
1643
1644 if format == 'short':
1645 return sprint_error(error_text)
1646
Michael Walsh7423c012016-10-04 10:27:21 -05001647 buffer = ""
1648 buffer += sprint_dashes(width=120, char="=")
1649 buffer += sprint_error(error_text)
1650 buffer += "\n"
1651 # Calling sprint_call_stack with stack_frame_ix of 0 causes it to show
1652 # itself and this function in the call stack. This is not helpful to a
1653 # debugger and is therefore clutter. We will adjust the stack_frame_ix to
1654 # hide that information.
Michael Walsh9c75f672017-09-12 17:11:35 -05001655 stack_frame_ix = 1
Michael Walsh7423c012016-10-04 10:27:21 -05001656 caller_func_name = sprint_func_name(2)
1657 if caller_func_name.endswith("print_error_report"):
1658 stack_frame_ix += 1
Michael Walsh7bfa9ab2018-11-16 15:24:26 -06001659 buffer += sprint_call_stack(indent, stack_frame_ix)
Michael Walsh7423c012016-10-04 10:27:21 -05001660 buffer += sprint_pgm_header(indent)
1661 buffer += sprint_dashes(width=120, char="=")
1662
1663 return buffer
1664
Michael Walsh7423c012016-10-04 10:27:21 -05001665
Michael Walsh18176322016-11-15 15:11:21 -06001666def sprint_issuing(cmd_buf,
1667 test_mode=0):
Michael Walshde791732016-09-06 14:25:24 -05001668 r"""
1669 Return a line indicating a command that the program is about to execute.
1670
1671 Sample output for a cmd_buf of "ls"
1672
1673 #(CDT) 2016/08/25 17:57:36 - Issuing: ls
Michael Walshbec416d2016-11-10 08:54:52 -06001674
Michael Walsh4dbb6002019-05-17 15:51:15 -05001675 Description of argument(s):
Michael Walshde791732016-09-06 14:25:24 -05001676 cmd_buf The command to be executed by caller.
Michael Walsh4dbb6002019-05-17 15:51:15 -05001677 test_mode With test_mode set, the output will look
Michael Walshbec416d2016-11-10 08:54:52 -06001678 like this:
1679
1680 #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls
1681
Michael Walshde791732016-09-06 14:25:24 -05001682 """
1683
Michael Walshbec416d2016-11-10 08:54:52 -06001684 buffer = sprint_time()
1685 if test_mode:
1686 buffer += "(test_mode) "
Michael Walsh61c12982019-03-28 12:38:01 -05001687 if type(cmd_buf) is list:
1688 # Assume this is a robot command in the form of a list.
1689 cmd_buf = ' '.join([str(element) for element in cmd_buf])
Michael Walshbec416d2016-11-10 08:54:52 -06001690 buffer += "Issuing: " + cmd_buf + "\n"
Michael Walshde791732016-09-06 14:25:24 -05001691
1692 return buffer
1693
Michael Walshde791732016-09-06 14:25:24 -05001694
Michael Walshde791732016-09-06 14:25:24 -05001695def sprint_pgm_footer():
Michael Walshde791732016-09-06 14:25:24 -05001696 r"""
1697 Return a standardized footer that programs should print at the end of the
1698 program run. It includes useful information like total run time, etc.
1699 """
1700
1701 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n"
1702
1703 total_time = time.time() - start_time
1704 total_time_string = "%0.6f" % total_time
1705
Michael Walsh7423c012016-10-04 10:27:21 -05001706 buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string)
Michael Walshbec416d2016-11-10 08:54:52 -06001707 buffer += "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001708
1709 return buffer
1710
Michael Walsh7423c012016-10-04 10:27:21 -05001711
Michael Walsh7423c012016-10-04 10:27:21 -05001712def sprint(buffer=""):
Michael Walsh7423c012016-10-04 10:27:21 -05001713 r"""
1714 Simply return the user's buffer. This function is used by the qprint and
1715 dprint functions defined dynamically below, i.e. it would not normally be
1716 called for general use.
1717
Michael Walsh4dbb6002019-05-17 15:51:15 -05001718 Description of argument(s).
Michael Walsh7423c012016-10-04 10:27:21 -05001719 buffer This will be returned to the caller.
1720 """
Michael Walshde791732016-09-06 14:25:24 -05001721
Michael Walsh95e45102018-02-09 12:44:43 -06001722 try:
1723 return str(buffer)
1724 except UnicodeEncodeError:
1725 return buffer
Michael Walshbec416d2016-11-10 08:54:52 -06001726
Michael Walshbec416d2016-11-10 08:54:52 -06001727
Michael Walshbec416d2016-11-10 08:54:52 -06001728def sprintn(buffer=""):
Michael Walshbec416d2016-11-10 08:54:52 -06001729 r"""
1730 Simply return the user's buffer with a line feed. This function is used
1731 by the qprint and dprint functions defined dynamically below, i.e. it
1732 would not normally be called for general use.
1733
Michael Walsh4dbb6002019-05-17 15:51:15 -05001734 Description of argument(s).
Michael Walshbec416d2016-11-10 08:54:52 -06001735 buffer This will be returned to the caller.
1736 """
1737
Michael Walsh95e45102018-02-09 12:44:43 -06001738 try:
1739 buffer = str(buffer) + "\n"
1740 except UnicodeEncodeError:
1741 buffer = buffer + "\n"
Michael Walshbec416d2016-11-10 08:54:52 -06001742
Michael Walshde791732016-09-06 14:25:24 -05001743 return buffer
1744
Michael Walsh168eb0f2017-12-01 15:35:32 -06001745
Michael Walshfd2733c2017-11-13 11:36:20 -06001746def gp_print(buffer,
1747 stream='stdout'):
Michael Walshfd2733c2017-11-13 11:36:20 -06001748 r"""
1749 Print the buffer using either sys.stdout.write or BuiltIn().log_to_console
1750 depending on whether we are running in a robot environment.
1751
1752 This function is intended for use only by other functions in this module.
1753
Michael Walsh4dbb6002019-05-17 15:51:15 -05001754 Description of argument(s):
Michael Walshfd2733c2017-11-13 11:36:20 -06001755 buffer The string to be printed.
1756 stream Either "stdout" or "stderr".
1757 """
1758
1759 if robot_env:
1760 BuiltIn().log_to_console(buffer, stream=stream, no_newline=True)
1761 else:
1762 if stream == "stdout":
1763 sys.stdout.write(buffer)
1764 sys.stdout.flush()
1765 else:
1766 sys.stderr.write(buffer)
1767 sys.stderr.flush()
Michael Walshde791732016-09-06 14:25:24 -05001768
1769
Michael Walsh168eb0f2017-12-01 15:35:32 -06001770def gp_log(buffer):
Michael Walsh168eb0f2017-12-01 15:35:32 -06001771 r"""
1772 Log the buffer using either python logging or BuiltIn().log depending on
1773 whether we are running in a robot environment.
1774
1775 This function is intended for use only by other functions in this module.
1776
Michael Walsh4dbb6002019-05-17 15:51:15 -05001777 Description of argument(s):
Michael Walsh168eb0f2017-12-01 15:35:32 -06001778 buffer The string to be logged.
1779 """
1780
1781 if robot_env:
1782 BuiltIn().log(buffer)
1783 else:
1784 logging.warning(buffer)
1785
1786
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001787def gp_debug_print(buffer):
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001788 r"""
Michael Walshfd2733c2017-11-13 11:36:20 -06001789 Print with gp_print only if gen_print_debug is set.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001790
1791 This function is intended for use only by other functions in this module.
1792
Michael Walsh4dbb6002019-05-17 15:51:15 -05001793 Description of argument(s):
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001794 buffer The string to be printed.
1795 """
1796
1797 if not gen_print_debug:
1798 return
1799
Michael Walshfd2733c2017-11-13 11:36:20 -06001800 gp_print(buffer)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001801
1802
Michael Walshb1500152017-04-12 15:42:43 -05001803def get_var_value(var_value=None,
1804 default=1,
1805 var_name=None):
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001806 r"""
Michael Walshb1500152017-04-12 15:42:43 -05001807 Return either var_value, the corresponding global value or default.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001808
Michael Walshb1500152017-04-12 15:42:43 -05001809 If var_value is not None, it will simply be returned.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001810
Michael Walshb1500152017-04-12 15:42:43 -05001811 If var_value is None, this function will return the corresponding global
1812 value of the variable in question.
1813
1814 Note: For global values, if we are in a robot environment,
1815 get_variable_value will be used. Otherwise, the __builtin__ version of
1816 the variable is returned (which are set by gen_arg.py functions).
1817
1818 If there is no global value associated with the variable, default is
1819 returned.
1820
1821 This function is useful for other functions in setting default values for
1822 parameters.
1823
1824 Example use:
1825
1826 def my_func(quiet=None):
1827
1828 quiet = int(get_var_value(quiet, 0))
1829
1830 Example calls to my_func():
1831
1832 In the following example, the caller is explicitly asking to have quiet be
1833 set to 1.
1834
1835 my_func(quiet=1)
1836
1837 In the following example, quiet will be set to the global value of quiet,
1838 if defined, or to 0 (the default).
1839
1840 my_func()
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001841
Michael Walsh4dbb6002019-05-17 15:51:15 -05001842 Description of argument(s):
Michael Walshb1500152017-04-12 15:42:43 -05001843 var_value The value to be returned (if not equal to
1844 None).
1845 default The value that is returned if var_value is
1846 None and there is no corresponding global
1847 value defined.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001848 var_name The name of the variable whose value is to
Michael Walshb1500152017-04-12 15:42:43 -05001849 be returned. Under most circumstances,
1850 this value need not be provided. This
1851 function can figure out the name of the
1852 variable passed as var_value. One
1853 exception to this would be if this
1854 function is called directly from a .robot
1855 file.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001856 """
1857
Michael Walshb1500152017-04-12 15:42:43 -05001858 if var_value is not None:
1859 return var_value
1860
1861 if var_name is None:
1862 var_name = get_arg_name(None, 1, 2)
1863
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001864 if robot_env:
Michael Walshc6537442017-06-06 15:33:52 -05001865 var_value = BuiltIn().get_variable_value("${" + var_name + "}",
1866 default)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001867 else:
1868 var_value = getattr(__builtin__, var_name, default)
1869
1870 return var_value
1871
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001872
Michael Walsh052ff812018-05-18 16:09:09 -05001873def get_stack_var(var_name,
1874 default="",
1875 init_stack_ix=2):
Michael Walsh052ff812018-05-18 16:09:09 -05001876 r"""
1877 Starting with the caller's stack level, search upward in the call stack,
1878 for a variable named var_name and return its value. If the variable
1879 cannot be found, return default.
1880
1881 Example code:
1882
1883 def func12():
1884 my_loc_var1 = get_stack_var('my_var1', "default value")
1885
1886 def func11():
1887 my_var1 = 11
1888 func12()
1889
1890 In this example, get_stack_var will find the value of my_var1 in func11's
1891 stack and will therefore return the value 11. Therefore, my_loc_var1
1892 would get set to 11.
1893
1894 Description of argument(s):
1895 var_name The name of the variable to be searched
1896 for.
1897 default The value to return if the the variable
1898 cannot be found.
1899 init_stack_ix The initial stack index from which to
1900 begin the search. 0 would be the index of
1901 this func1tion ("get_stack_var"), 1 would
1902 be the index of the function calling this
1903 function, etc.
1904 """
1905
Michael Walsh6f0362c2019-03-25 14:05:14 -05001906 work_around_inspect_stack_cwd_failure()
Michael Walsh052ff812018-05-18 16:09:09 -05001907 return next((frame[0].f_locals[var_name]
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05001908 for frame in inspect.stack()[init_stack_ix:]
1909 if var_name in frame[0].f_locals), default)
Michael Walsh052ff812018-05-18 16:09:09 -05001910
1911
Michael Walsh82acf002017-05-04 14:33:05 -05001912# hidden_text is a list of passwords which are to be replaced with asterisks
1913# by print functions defined in this module.
1914hidden_text = []
1915# password_regex is created based on the contents of hidden_text.
1916password_regex = ""
1917
1918
Michael Walsh82acf002017-05-04 14:33:05 -05001919def register_passwords(*args):
Michael Walsh82acf002017-05-04 14:33:05 -05001920 r"""
1921 Register one or more passwords which are to be hidden in output produced
1922 by the print functions in this module.
1923
1924 Note: Blank password values are NOT registered. They are simply ignored.
1925
1926 Description of argument(s):
1927 args One or more password values. If a given
1928 password value is already registered, this
1929 function will simply do nothing.
1930 """
1931
1932 global hidden_text
1933 global password_regex
1934
1935 for password in args:
1936 if password == "":
1937 break
1938 if password in hidden_text:
1939 break
1940
1941 # Place the password into the hidden_text list.
1942 hidden_text.append(password)
1943 # Create a corresponding password regular expression. Escape regex
1944 # special characters too.
1945 password_regex = '(' +\
1946 '|'.join([re.escape(x) for x in hidden_text]) + ')'
1947
Michael Walsh82acf002017-05-04 14:33:05 -05001948
Michael Walsh82acf002017-05-04 14:33:05 -05001949def replace_passwords(buffer):
Michael Walsh82acf002017-05-04 14:33:05 -05001950 r"""
1951 Return the buffer but with all registered passwords replaced by a string
1952 of asterisks.
1953
1954
1955 Description of argument(s):
1956 buffer The string to be returned but with
1957 passwords replaced.
1958 """
1959
1960 global password_regex
1961
1962 if int(os.environ.get("DEBUG_SHOW_PASSWORDS", "0")):
1963 return buffer
1964
1965 if password_regex == "":
1966 # No passwords to replace.
1967 return buffer
1968
1969 return re.sub(password_regex, "********", buffer)
1970
Michael Walshfd2733c2017-11-13 11:36:20 -06001971
1972def create_print_wrapper_funcs(func_names,
1973 stderr_func_names,
Michael Walsh61c12982019-03-28 12:38:01 -05001974 replace_dict,
1975 func_prefix=""):
Michael Walshfd2733c2017-11-13 11:36:20 -06001976 r"""
1977 Generate code for print wrapper functions and return the generated code as
1978 a string.
1979
1980 To illustrate, suppose there is a "print_foo_bar" function in the
1981 func_names list.
1982 This function will...
1983 - Expect that there is an sprint_foo_bar function already in existence.
1984 - Create a print_foo_bar function which calls sprint_foo_bar and prints
Michael Walshfaafa9c2018-06-27 16:39:31 -05001985 the result.
Michael Walshfd2733c2017-11-13 11:36:20 -06001986 - Create a qprint_foo_bar function which calls upon sprint_foo_bar only if
Michael Walshfaafa9c2018-06-27 16:39:31 -05001987 global value quiet is 0.
Michael Walshfd2733c2017-11-13 11:36:20 -06001988 - Create a dprint_foo_bar function which calls upon sprint_foo_bar only if
Michael Walshfaafa9c2018-06-27 16:39:31 -05001989 global value debug is 1.
Michael Walshfd2733c2017-11-13 11:36:20 -06001990
1991 Also, code will be generated to define aliases for each function as well.
1992 Each alias will be created by replacing "print_" in the function name with
1993 "p" For example, the alias for print_foo_bar will be pfoo_bar.
1994
1995 Description of argument(s):
1996 func_names A list of functions for which print
1997 wrapper function code is to be generated.
1998 stderr_func_names A list of functions whose generated code
1999 should print to stderr rather than to
2000 stdout.
2001 replace_dict Please see the create_func_def_string
2002 function in wrap_utils.py for details on
2003 this parameter. This parameter will be
2004 passed directly to create_func_def_string.
Michael Walsh61c12982019-03-28 12:38:01 -05002005 func_prefix Prefix to be pre-pended to the generated
2006 function name.
Michael Walshfd2733c2017-11-13 11:36:20 -06002007 """
2008
2009 buffer = ""
2010
2011 for func_name in func_names:
2012 if func_name in stderr_func_names:
2013 replace_dict['output_stream'] = "stderr"
2014 else:
2015 replace_dict['output_stream'] = "stdout"
2016
2017 s_func_name = "s" + func_name
2018 q_func_name = "q" + func_name
2019 d_func_name = "d" + func_name
2020
2021 # We don't want to try to redefine the "print" function, thus the
2022 # following if statement.
2023 if func_name != "print":
Michael Walsh61c12982019-03-28 12:38:01 -05002024 func_def = create_func_def_string(s_func_name,
2025 func_prefix + func_name,
Michael Walshfd2733c2017-11-13 11:36:20 -06002026 print_func_template,
2027 replace_dict)
2028 buffer += func_def
2029
Michael Walsh61c12982019-03-28 12:38:01 -05002030 func_def = create_func_def_string(s_func_name,
2031 func_prefix + "q" + func_name,
Michael Walshfd2733c2017-11-13 11:36:20 -06002032 qprint_func_template, replace_dict)
2033 buffer += func_def
2034
Michael Walsh61c12982019-03-28 12:38:01 -05002035 func_def = create_func_def_string(s_func_name,
2036 func_prefix + "d" + func_name,
Michael Walshfd2733c2017-11-13 11:36:20 -06002037 dprint_func_template, replace_dict)
2038 buffer += func_def
2039
Michael Walsh61c12982019-03-28 12:38:01 -05002040 func_def = create_func_def_string(s_func_name,
2041 func_prefix + "l" + func_name,
Michael Walsh168eb0f2017-12-01 15:35:32 -06002042 lprint_func_template, replace_dict)
2043 buffer += func_def
2044
Michael Walshfd2733c2017-11-13 11:36:20 -06002045 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var).
2046 alias = re.sub("print_", "p", func_name)
2047 alias = re.sub("print", "p", alias)
Michael Walsh61c12982019-03-28 12:38:01 -05002048 prefixes = [func_prefix + "", "s", func_prefix + "q",
2049 func_prefix + "d", func_prefix + "l"]
Michael Walshfd2733c2017-11-13 11:36:20 -06002050 for prefix in prefixes:
2051 if alias == "p":
2052 continue
2053 func_def = prefix + alias + " = " + prefix + func_name
2054 buffer += func_def + "\n"
2055
2056 return buffer
Michael Walsh82acf002017-05-04 14:33:05 -05002057
2058
Michael Walshde791732016-09-06 14:25:24 -05002059# In the following section of code, we will dynamically create print versions
2060# for each of the sprint functions defined above. So, for example, where we
2061# have an sprint_time() function defined above that returns the time to the
Michael Walsh7423c012016-10-04 10:27:21 -05002062# caller in a string, we will create a corresponding print_time() function
2063# that will print that string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -05002064
Michael Walsh61c12982019-03-28 12:38:01 -05002065# It can be complicated to follow what's being created below. Here is an
Michael Walshfd2733c2017-11-13 11:36:20 -06002066# example of the print_time() function that will be created:
Michael Walshde791732016-09-06 14:25:24 -05002067
Michael Walshfd2733c2017-11-13 11:36:20 -06002068# def print_time(buffer=''):
Michael Walsh61c12982019-03-28 12:38:01 -05002069# gp_print(replace_passwords(sprint_time(buffer=buffer)), stream='stdout')
2070
2071# For each print function defined below, there will also be a qprint, a
2072# dprint and an lprint version defined (e.g. qprint_time, dprint_time,
2073# lprint_time).
2074
2075# The q version of each print function will only print if the quiet variable
2076# is 0.
2077# The d version of each print function will only print if the debug variable
2078# is 1.
2079# The l version of each print function will print the contents as log data.
2080# For conventional programs, this means use of the logging module. For robot
2081# programs it means use of the BuiltIn().log() function.
Michael Walshde791732016-09-06 14:25:24 -05002082
Michael Walshfd2733c2017-11-13 11:36:20 -06002083# Templates for the various print wrapper functions.
2084print_func_template = \
2085 [
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -05002086 " <mod_qualifier>gp_print(<mod_qualifier>replace_passwords("
2087 + "<call_line>), stream='<output_stream>')"
Michael Walshfd2733c2017-11-13 11:36:20 -06002088 ]
2089
2090qprint_func_template = \
2091 [
Michael Walsh589ae762019-03-19 13:22:39 -05002092 " quiet_default = <mod_qualifier>get_var_value(None, 0, \"quiet\")",
2093 " quiet = <mod_qualifier>get_stack_var(\"quiet\", quiet_default)",
2094 " if int(quiet): return"
Michael Walshfd2733c2017-11-13 11:36:20 -06002095 ] + print_func_template
2096
2097dprint_func_template = \
2098 [
Michael Walsh589ae762019-03-19 13:22:39 -05002099 " debug_default = <mod_qualifier>get_var_value(None, 0, \"debug\")",
2100 " debug = <mod_qualifier>get_stack_var(\"debug\", debug_default)",
2101 " if not int(debug): return"
Michael Walshfd2733c2017-11-13 11:36:20 -06002102 ] + print_func_template
2103
Michael Walsh168eb0f2017-12-01 15:35:32 -06002104lprint_func_template = \
2105 [
Michael Walsh61c12982019-03-28 12:38:01 -05002106 " <mod_qualifier>set_last_seconds_ix(<mod_qualifier>"
2107 + "lprint_last_seconds_ix())",
2108 " <mod_qualifier>gp_log(<mod_qualifier>replace_passwords"
2109 + "(<call_line>))",
2110 " <mod_qualifier>set_last_seconds_ix(<mod_qualifier>"
2111 + "standard_print_last_seconds_ix())"
Michael Walsh168eb0f2017-12-01 15:35:32 -06002112 ]
2113
Michael Walsh81c02342018-01-05 15:43:28 -06002114replace_dict = {'output_stream': 'stdout', 'mod_qualifier': ''}
Michael Walshfd2733c2017-11-13 11:36:20 -06002115
Michael Walsh61c12982019-03-28 12:38:01 -05002116gp_debug_print("robot_env: " + str(robot_env) + "\n")
Michael Walshde791732016-09-06 14:25:24 -05002117
2118# func_names contains a list of all print functions which should be created
2119# from their sprint counterparts.
2120func_names = ['print_time', 'print_timen', 'print_error', 'print_varx',
Michael Walsh18176322016-11-15 15:11:21 -06002121 'print_var', 'print_vars', 'print_dashes', 'indent',
2122 'print_call_stack', 'print_func_name', 'print_executing',
2123 'print_pgm_header', 'print_issuing', 'print_pgm_footer',
2124 'print_error_report', 'print', 'printn']
Michael Walshde791732016-09-06 14:25:24 -05002125
Michael Walsh2ee77cd2017-03-08 11:50:17 -06002126# stderr_func_names is a list of functions whose output should go to stderr
2127# rather than stdout.
2128stderr_func_names = ['print_error', 'print_error_report']
Michael Walshde791732016-09-06 14:25:24 -05002129
Michael Walshfd2733c2017-11-13 11:36:20 -06002130func_defs = create_print_wrapper_funcs(func_names, stderr_func_names,
2131 replace_dict)
2132gp_debug_print(func_defs)
2133exec(func_defs)