blob: e5e74d8e8029c1d126885a7635835d96b8f35b1a [file] [log] [blame]
Michael Walshde791732016-09-06 14:25:24 -05001#!/usr/bin/env python
2
3r"""
4This module provides many valuable print functions such as sprint_var,
5sprint_time, sprint_error, sprint_call_stack.
6"""
7
8import sys
9import os
10import time
11import inspect
12import re
13import grp
14import socket
15import argparse
Michael Walsh7423c012016-10-04 10:27:21 -050016import __builtin__
17import logging
Michael Walshbec416d2016-11-10 08:54:52 -060018import collections
19
Michael Walshbec416d2016-11-10 08:54:52 -060020try:
Michael Walsh2ee77cd2017-03-08 11:50:17 -060021 robot_env = 1
Michael Walshbec416d2016-11-10 08:54:52 -060022 from robot.utils import DotDict
Michael Walsh8e6deb42017-01-27 14:22:41 -060023 from robot.utils import NormalizedDict
Michael Walsh2ee77cd2017-03-08 11:50:17 -060024 from robot.libraries.BuiltIn import BuiltIn
Michael Walshbec416d2016-11-10 08:54:52 -060025except ImportError:
Michael Walsh2ee77cd2017-03-08 11:50:17 -060026 robot_env = 0
Michael Walsh7423c012016-10-04 10:27:21 -050027
28import gen_arg as ga
Michael Walshde791732016-09-06 14:25:24 -050029
30# Setting these variables for use both inside this module and by programs
31# importing this module.
32pgm_dir_path = sys.argv[0]
33pgm_name = os.path.basename(pgm_dir_path)
Michael Walsh7423c012016-10-04 10:27:21 -050034pgm_dir_name = re.sub("/" + pgm_name, "", pgm_dir_path) + "/"
35
Michael Walshde791732016-09-06 14:25:24 -050036
37# Some functions (e.g. sprint_pgm_header) have need of a program name value
38# that looks more like a valid variable name. Therefore, we'll swap odd
39# characters like "." out for underscores.
40pgm_name_var_name = pgm_name.replace(".", "_")
41
42# Initialize global values used as defaults by print_time, print_var, etc.
43col1_indent = 0
44
45# Calculate default column width for print_var functions based on environment
46# variable settings. The objective is to make the variable values line up
47# nicely with the time stamps.
48col1_width = 29
49if 'NANOSECONDS' in os.environ:
50 NANOSECONDS = os.environ['NANOSECONDS']
51else:
52 NANOSECONDS = 0
53
54if NANOSECONDS == "1":
55 col1_width = col1_width + 7
56
57if 'SHOW_ELAPSED_TIME' in os.environ:
58 SHOW_ELAPSED_TIME = os.environ['SHOW_ELAPSED_TIME']
59else:
60 SHOW_ELAPSED_TIME = 0
61
62if SHOW_ELAPSED_TIME == "1":
63 if NANOSECONDS == "1":
64 col1_width = col1_width + 14
65 else:
66 col1_width = col1_width + 7
67
68# Initialize some time variables used in module functions.
69start_time = time.time()
70sprint_time_last_seconds = start_time
71
Michael Walsh2ee77cd2017-03-08 11:50:17 -060072# The user can set environment variable "GEN_PRINT_DEBUG" to get debug output
73# from this module.
74gen_print_debug = int(os.environ.get('GEN_PRINT_DEBUG', 0))
Michael Walsh7423c012016-10-04 10:27:21 -050075
Michael Walshde791732016-09-06 14:25:24 -050076
77###############################################################################
78def sprint_func_name(stack_frame_ix=None):
79
80 r"""
81 Return the function name associated with the indicated stack frame.
82
83 Description of arguments:
84 stack_frame_ix The index of the stack frame whose
85 function name should be returned. If the
Michael Walsh2ee77cd2017-03-08 11:50:17 -060086 caller does not specify a value, this
Michael Walshde791732016-09-06 14:25:24 -050087 function will set the value to 1 which is
88 the index of the caller's stack frame. If
89 the caller is the wrapper function
90 "print_func_name", this function will bump
91 it up by 1.
92 """
93
94 # If user specified no stack_frame_ix, we'll set it to a proper default
95 # value.
96 if stack_frame_ix is None:
97 func_name = sys._getframe().f_code.co_name
98 caller_func_name = sys._getframe(1).f_code.co_name
99 if func_name[1:] == caller_func_name:
100 stack_frame_ix = 2
101 else:
102 stack_frame_ix = 1
103
104 func_name = sys._getframe(stack_frame_ix).f_code.co_name
105
106 return func_name
107
108###############################################################################
109
110
111# get_arg_name is not a print function per se. I have included it in this
112# module because it is used by sprint_var which is found in this module.
113###############################################################################
114def get_arg_name(var,
115 arg_num=1,
116 stack_frame_ix=1):
117
118 r"""
119 Return the "name" of an argument passed to a function. This could be a
120 literal or a variable name.
121
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600122 Description of arguments:
Michael Walshde791732016-09-06 14:25:24 -0500123 var The variable whose name you want returned.
124 arg_num The arg number (1 through n) whose name
125 you wish to have returned. This value
126 should not exceed the number of arguments
127 allowed by the target function.
128 stack_frame_ix The stack frame index of the target
129 function. This value must be 1 or
130 greater. 1 would indicate get_arg_name's
131 stack frame. 2 would be the caller of
132 get_arg_name's stack frame, etc.
133
134 Example 1:
135
136 my_var = "mike"
137 var_name = get_arg_name(my_var)
138
139 In this example, var_name will receive the value "my_var".
140
141 Example 2:
142
143 def test1(var):
144 # Getting the var name of the first arg to this function, test1.
145 # Note, in this case, it doesn't matter what you pass as the first arg
146 # to get_arg_name since it is the caller's variable name that matters.
147 dummy = 1
148 arg_num = 1
149 stack_frame = 2
150 var_name = get_arg_name(dummy, arg_num, stack_frame)
151
152 # Mainline...
153
154 another_var = "whatever"
155 test1(another_var)
156
157 In this example, var_name will be set to "another_var".
158
159 """
160
161 # Note: I wish to avoid recursion so I refrain from calling any function
162 # that calls this function (i.e. sprint_var, valid_value, etc.).
163
Michael Walsh23e7f492017-01-10 11:34:47 -0600164 # The user can set environment variable "GET_ARG_NAME_DEBUG" to get debug
165 # output from this function.
166 local_debug = int(os.environ.get('GET_ARG_NAME_DEBUG', 0))
167 # In addition to GET_ARG_NAME_DEBUG, the user can set environment
168 # variable "GET_ARG_NAME_SHOW_SOURCE" to have this function include source
169 # code in the debug output.
170 local_debug_show_source = int(
171 os.environ.get('GET_ARG_NAME_SHOW_SOURCE', 0))
Michael Walshde791732016-09-06 14:25:24 -0500172
173 if arg_num < 1:
174 print_error("Programmer error - Variable \"arg_num\" has an invalid" +
175 " value of \"" + str(arg_num) + "\". The value must be" +
176 " an integer that is greater than 0.\n")
177 # What is the best way to handle errors? Raise exception? I'll
178 # revisit later.
179 return
180 if stack_frame_ix < 1:
181 print_error("Programmer error - Variable \"stack_frame_ix\" has an" +
182 " invalid value of \"" + str(stack_frame_ix) + "\". The" +
183 " value must be an integer that is greater than or equal" +
184 " to 1.\n")
185 return
186
187 if local_debug:
188 debug_indent = 2
Michael Walsh23e7f492017-01-10 11:34:47 -0600189 print("")
190 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500191 print(sprint_func_name() + "() parms:")
192 print_varx("var", var, 0, debug_indent)
193 print_varx("arg_num", arg_num, 0, debug_indent)
194 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600195 print("")
196 print_call_stack(debug_indent, 2)
Michael Walshde791732016-09-06 14:25:24 -0500197
Michael Walsh23e7f492017-01-10 11:34:47 -0600198 for count in range(0, 2):
199 try:
200 frame, filename, cur_line_no, function_name, lines, index = \
201 inspect.stack()[stack_frame_ix]
202 except IndexError:
203 print_error("Programmer error - The caller has asked for" +
204 " information about the stack frame at index \"" +
205 str(stack_frame_ix) + "\". However, the stack" +
206 " only contains " + str(len(inspect.stack())) +
207 " entries. Therefore the stack frame index is out" +
208 " of range.\n")
209 return
210 if filename != "<string>":
211 break
212 # filename of "<string>" may mean that the function in question was
213 # defined dynamically and therefore its code stack is inaccessible.
214 # This may happen with functions like "rqprint_var". In this case,
215 # we'll increment the stack_frame_ix and try again.
216 stack_frame_ix += 1
217 if local_debug:
218 print("Adjusted stack_frame_ix...")
219 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500220
221 called_func_name = sprint_func_name(stack_frame_ix)
Michael Walsh23e7f492017-01-10 11:34:47 -0600222
223 module = inspect.getmodule(frame)
224
225 # Though I would expect inspect.getsourcelines(frame) to get all module
226 # source lines if the frame is "<module>", it doesn't do that. Therefore,
227 # for this special case, I will do inspect.getsourcelines(module).
228 if function_name == "<module>":
229 source_lines, source_line_num =\
230 inspect.getsourcelines(module)
231 line_ix = cur_line_no - source_line_num - 1
232 else:
233 source_lines, source_line_num =\
234 inspect.getsourcelines(frame)
235 line_ix = cur_line_no - source_line_num
236
237 if local_debug:
238 print("\n Variables retrieved from inspect.stack() function:")
239 print_varx("frame", frame, 0, debug_indent + 2)
240 print_varx("filename", filename, 0, debug_indent + 2)
241 print_varx("cur_line_no", cur_line_no, 0, debug_indent + 2)
242 print_varx("function_name", function_name, 0, debug_indent + 2)
243 print_varx("lines", lines, 0, debug_indent + 2)
244 print_varx("index", index, 0, debug_indent + 2)
245 print_varx("source_line_num", source_line_num, 0, debug_indent)
246 print_varx("line_ix", line_ix, 0, debug_indent)
247 if local_debug_show_source:
248 print_varx("source_lines", source_lines, 0, debug_indent)
249 print_varx("called_func_name", called_func_name, 0, debug_indent)
250
251 # Get a list of all functions defined for the module. Note that this
252 # doesn't work consistently when _run_exitfuncs is at the top of the stack
253 # (i.e. if we're running an exit function). I've coded a work-around
254 # below for this deficiency.
255 all_functions = inspect.getmembers(module, inspect.isfunction)
256
257 # Get called_func_id by searching for our function in the list of all
258 # functions.
259 called_func_id = None
260 for func_name, function in all_functions:
261 if func_name == called_func_name:
262 called_func_id = id(function)
263 break
264 # NOTE: The only time I've found that called_func_id can't be found is
265 # when we're running from an exit function.
266
267 # Look for other functions in module with matching id.
268 aliases = set([called_func_name])
269 for func_name, function in all_functions:
270 if func_name == called_func_name:
271 continue
272 func_id = id(function)
273 if func_id == called_func_id:
274 aliases.add(func_name)
275
276 # In most cases, my general purpose code above will find all aliases.
277 # However, for the odd case (i.e. running from exit function), I've added
278 # code to handle pvar, qpvar, dpvar, etc. aliases explicitly since they
279 # are defined in this module and used frequently.
280 # pvar is an alias for print_var.
281 aliases.add(re.sub("print_var", "pvar", called_func_name))
282
283 func_regex = ".*(" + '|'.join(aliases) + ")[ ]*\("
284
285 # Search backward through source lines looking for the calling function
286 # name.
287 found = False
288 for start_line_ix in range(line_ix, 0, -1):
289 # Skip comment lines.
290 if re.match(r"[ ]*#", source_lines[start_line_ix]):
291 continue
292 if re.match(func_regex, source_lines[start_line_ix]):
293 found = True
294 break
295 if not found:
296 print_error("Programmer error - Could not find the source line with" +
297 " a reference to function \"" + called_func_name + "\".\n")
298 return
299
300 # Search forward through the source lines looking for a line with the
301 # same indentation as the start time. The end of our composite line
302 # should be the line preceding that line.
303 start_indent = len(source_lines[start_line_ix]) -\
304 len(source_lines[start_line_ix].lstrip(' '))
305 end_line_ix = line_ix
306 for end_line_ix in range(line_ix + 1, len(source_lines)):
307 if source_lines[end_line_ix].strip() == "":
308 continue
309 line_indent = len(source_lines[end_line_ix]) -\
310 len(source_lines[end_line_ix].lstrip(' '))
311 if line_indent == start_indent:
312 end_line_ix -= 1
313 break
314
315 # Join the start line through the end line into a composite line.
316 composite_line = ''.join(map(str.strip,
317 source_lines[start_line_ix:end_line_ix + 1]))
Michael Walsh7423c012016-10-04 10:27:21 -0500318
Michael Walshbec416d2016-11-10 08:54:52 -0600319 # arg_list_etc = re.sub(".*" + called_func_name, "", composite_line)
320 arg_list_etc = "(" + re.sub(func_regex, "", composite_line)
Michael Walshde791732016-09-06 14:25:24 -0500321 if local_debug:
Michael Walsh23e7f492017-01-10 11:34:47 -0600322 print_varx("aliases", aliases, 0, debug_indent)
Michael Walshbec416d2016-11-10 08:54:52 -0600323 print_varx("func_regex", func_regex, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600324 print_varx("start_line_ix", start_line_ix, 0, debug_indent)
325 print_varx("end_line_ix", end_line_ix, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500326 print_varx("composite_line", composite_line, 0, debug_indent)
327 print_varx("arg_list_etc", arg_list_etc, 0, debug_indent)
328
329 # Parse arg list...
330 # Initialize...
331 nest_level = -1
332 arg_ix = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500333 args_list = [""]
Michael Walshde791732016-09-06 14:25:24 -0500334 for ix in range(0, len(arg_list_etc)):
335 char = arg_list_etc[ix]
336 # Set the nest_level based on whether we've encounted a parenthesis.
337 if char == "(":
338 nest_level += 1
339 if nest_level == 0:
340 continue
341 elif char == ")":
342 nest_level -= 1
343 if nest_level < 0:
344 break
345
346 # If we reach a comma at base nest level, we are done processing an
Michael Walsh7423c012016-10-04 10:27:21 -0500347 # argument so we increment arg_ix and initialize a new args_list entry.
Michael Walshde791732016-09-06 14:25:24 -0500348 if char == "," and nest_level == 0:
349 arg_ix += 1
Michael Walsh7423c012016-10-04 10:27:21 -0500350 args_list.append("")
Michael Walshde791732016-09-06 14:25:24 -0500351 continue
352
Michael Walsh7423c012016-10-04 10:27:21 -0500353 # For any other character, we append it it to the current arg list
Michael Walshde791732016-09-06 14:25:24 -0500354 # entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500355 args_list[arg_ix] += char
Michael Walshde791732016-09-06 14:25:24 -0500356
357 # Trim whitespace from each list entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500358 args_list = [arg.strip() for arg in args_list]
Michael Walshde791732016-09-06 14:25:24 -0500359
Michael Walsh7423c012016-10-04 10:27:21 -0500360 if arg_num > len(args_list):
Michael Walshde791732016-09-06 14:25:24 -0500361 print_error("Programmer error - The caller has asked for the name of" +
362 " argument number \"" + str(arg_num) + "\" but there " +
Michael Walsh7423c012016-10-04 10:27:21 -0500363 "were only \"" + str(len(args_list)) + "\" args used:\n" +
364 sprint_varx("args_list", args_list))
Michael Walshde791732016-09-06 14:25:24 -0500365 return
366
Michael Walsh7423c012016-10-04 10:27:21 -0500367 argument = args_list[arg_num - 1]
Michael Walshde791732016-09-06 14:25:24 -0500368
369 if local_debug:
Michael Walsh7423c012016-10-04 10:27:21 -0500370 print_varx("args_list", args_list, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500371 print_varx("argument", argument, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600372 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500373
374 return argument
375
376###############################################################################
377
378
379###############################################################################
380def sprint_time(buffer=""):
381
382 r"""
383 Return the time in the following format.
384
385 Example:
386
387 The following python code...
388
389 sys.stdout.write(sprint_time())
390 sys.stdout.write("Hi.\n")
391
392 Will result in the following type of output:
393
394 #(CDT) 2016/07/08 15:25:35 - Hi.
395
396 Example:
397
398 The following python code...
399
400 sys.stdout.write(sprint_time("Hi.\n"))
401
402 Will result in the following type of output:
403
404 #(CDT) 2016/08/03 17:12:05 - Hi.
405
406 The following environment variables will affect the formatting as
407 described:
408 NANOSECONDS This will cause the time stamps to be
409 precise to the microsecond (Yes, it
410 probably should have been named
411 MICROSECONDS but the convention was set
412 long ago so we're sticking with it).
413 Example of the output when environment
414 variable NANOSECONDS=1.
415
416 #(CDT) 2016/08/03 17:16:25.510469 - Hi.
417
418 SHOW_ELAPSED_TIME This will cause the elapsed time to be
419 included in the output. This is the
420 amount of time that has elapsed since the
421 last time this function was called. The
422 precision of the elapsed time field is
423 also affected by the value of the
424 NANOSECONDS environment variable. Example
425 of the output when environment variable
426 NANOSECONDS=0 and SHOW_ELAPSED_TIME=1.
427
428 #(CDT) 2016/08/03 17:17:40 - 0 - Hi.
429
430 Example of the output when environment variable NANOSECONDS=1 and
431 SHOW_ELAPSED_TIME=1.
432
433 #(CDT) 2016/08/03 17:18:47.317339 - 0.000046 - Hi.
434
435 Description of arguments.
436 buffer This will be appended to the formatted
437 time string.
438 """
439
440 global NANOSECONDS
441 global SHOW_ELAPSED_TIME
442 global sprint_time_last_seconds
443
444 seconds = time.time()
445 loc_time = time.localtime(seconds)
446 nanoseconds = "%0.6f" % seconds
447 pos = nanoseconds.find(".")
448 nanoseconds = nanoseconds[pos:]
449
450 time_string = time.strftime("#(%Z) %Y/%m/%d %H:%M:%S", loc_time)
451 if NANOSECONDS == "1":
452 time_string = time_string + nanoseconds
453
454 if SHOW_ELAPSED_TIME == "1":
455 cur_time_seconds = seconds
456 math_string = "%9.9f" % cur_time_seconds + " - " + "%9.9f" % \
457 sprint_time_last_seconds
458 elapsed_seconds = eval(math_string)
459 if NANOSECONDS == "1":
460 elapsed_seconds = "%11.6f" % elapsed_seconds
461 else:
462 elapsed_seconds = "%4i" % elapsed_seconds
463 sprint_time_last_seconds = cur_time_seconds
464 time_string = time_string + " - " + elapsed_seconds
465
466 return time_string + " - " + buffer
467
468###############################################################################
469
470
471###############################################################################
472def sprint_timen(buffer=""):
473
474 r"""
475 Append a line feed to the buffer, pass it to sprint_time and return the
476 result.
477 """
478
479 return sprint_time(buffer + "\n")
480
481###############################################################################
482
483
484###############################################################################
485def sprint_error(buffer=""):
486
487 r"""
488 Return a standardized error string. This includes:
489 - A time stamp
490 - The "**ERROR**" string
491 - The caller's buffer string.
492
493 Example:
494
495 The following python code...
496
497 print(sprint_error("Oops.\n"))
498
499 Will result in the following type of output:
500
501 #(CDT) 2016/08/03 17:12:05 - **ERROR** Oops.
502
503 Description of arguments.
504 buffer This will be appended to the formatted
505 error string.
506 """
507
508 return sprint_time() + "**ERROR** " + buffer
509
510###############################################################################
511
512
513###############################################################################
514def sprint_varx(var_name,
515 var_value,
516 hex=0,
517 loc_col1_indent=col1_indent,
Michael Walsh7423c012016-10-04 10:27:21 -0500518 loc_col1_width=col1_width,
519 trailing_char="\n"):
Michael Walshde791732016-09-06 14:25:24 -0500520
521 r"""
522 Print the var name/value passed to it. If the caller lets loc_col1_width
523 default, the printing lines up nicely with output generated by the
524 print_time functions.
525
526 Note that the sprint_var function (defined below) can be used to call this
527 function so that the programmer does not need to pass the var_name.
528 sprint_var will figure out the var_name. The sprint_var function is the
529 one that would normally be used by the general user.
530
531 For example, the following python code:
532
533 first_name = "Mike"
534 print_time("Doing this...\n")
535 print_varx("first_name", first_name)
536 print_time("Doing that...\n")
537
538 Will generate output like this:
539
540 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this...
541 first_name: Mike
542 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that...
543
544 This function recognizes several complex types of data such as dict, list
545 or tuple.
546
547 For example, the following python code:
548
549 my_dict = dict(one=1, two=2, three=3)
550 print_var(my_dict)
551
552 Will generate the following output:
553
554 my_dict:
555 my_dict[three]: 3
556 my_dict[two]: 2
557 my_dict[one]: 1
558
559 Description of arguments.
560 var_name The name of the variable to be printed.
561 var_value The value of the variable to be printed.
562 hex This indicates that the value should be
563 printed in hex format. It is the user's
564 responsibility to ensure that a var_value
Michael Walshbec416d2016-11-10 08:54:52 -0600565 contains a valid hex number. For string
566 var_values, this will be interpreted as
567 show_blanks which means that blank values
Michael Walshd995cb02017-02-07 14:46:01 -0600568 will be printed as "<blank>". For dict
569 var_values, this will be interpreted as
570 terse format where keys are not repeated
571 in the output.
Michael Walshde791732016-09-06 14:25:24 -0500572 loc_col1_indent The number of spaces to indent the output.
573 loc_col1_width The width of the output column containing
574 the variable name. The default value of
575 this is adjusted so that the var_value
576 lines up with text printed via the
577 print_time function.
Michael Walsh7423c012016-10-04 10:27:21 -0500578 trailing_char The character to be used at the end of the
579 returned string. The default value is a
580 line feed.
581 """
Michael Walshde791732016-09-06 14:25:24 -0500582
583 # Determine the type
584 if type(var_value) in (int, float, bool, str, unicode) \
585 or var_value is None:
586 # The data type is simple in the sense that it has no subordinate
587 # parts.
Michael Walsh7423c012016-10-04 10:27:21 -0500588 # Adjust loc_col1_width.
589 loc_col1_width = loc_col1_width - loc_col1_indent
Michael Walshde791732016-09-06 14:25:24 -0500590 # See if the user wants the output in hex format.
591 if hex:
Michael Walsh18176322016-11-15 15:11:21 -0600592 if type(var_value) not in (int, long):
Michael Walshbec416d2016-11-10 08:54:52 -0600593 value_format = "%s"
Michael Walsh2795edc2016-12-13 16:00:33 -0600594 if var_value == "":
Michael Walshbec416d2016-11-10 08:54:52 -0600595 var_value = "<blank>"
596 else:
597 value_format = "0x%08x"
Michael Walshde791732016-09-06 14:25:24 -0500598 else:
599 value_format = "%s"
600 format_string = "%" + str(loc_col1_indent) + "s%-" \
Michael Walsh7423c012016-10-04 10:27:21 -0500601 + str(loc_col1_width) + "s" + value_format + trailing_char
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600602 return format_string % ("", str(var_name) + ":", var_value)
Michael Walshde791732016-09-06 14:25:24 -0500603 else:
604 # The data type is complex in the sense that it has subordinate parts.
605 format_string = "%" + str(loc_col1_indent) + "s%s\n"
606 buffer = format_string % ("", var_name + ":")
607 loc_col1_indent += 2
Michael Walsh7423c012016-10-04 10:27:21 -0500608 try:
609 length = len(var_value)
610 except TypeError:
Michael Walsh23e7f492017-01-10 11:34:47 -0600611 length = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500612 ix = 0
613 loc_trailing_char = "\n"
Michael Walshbec416d2016-11-10 08:54:52 -0600614 type_is_dict = 0
Michael Walsh23e7f492017-01-10 11:34:47 -0600615 if type(var_value) is dict:
616 type_is_dict = 1
Michael Walsh8e6deb42017-01-27 14:22:41 -0600617 try:
618 if type(var_value) is collections.OrderedDict:
619 type_is_dict = 1
620 except AttributeError:
621 pass
622 try:
623 if type(var_value) is DotDict:
624 type_is_dict = 1
625 except NameError:
626 pass
627 try:
628 if type(var_value) is NormalizedDict:
629 type_is_dict = 1
630 except NameError:
631 pass
Michael Walshbec416d2016-11-10 08:54:52 -0600632 if type_is_dict:
Michael Walshde791732016-09-06 14:25:24 -0500633 for key, value in var_value.iteritems():
Michael Walsh7423c012016-10-04 10:27:21 -0500634 ix += 1
635 if ix == length:
636 loc_trailing_char = trailing_char
Michael Walshd995cb02017-02-07 14:46:01 -0600637 if hex:
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600638 # Since hex is being used as a format type, we want it
639 # turned off when processing integer dictionary values so
640 # it is not interpreted as a hex indicator.
641 loc_hex = not (type(value) is int)
Michael Walshd995cb02017-02-07 14:46:01 -0600642 buffer += sprint_varx(key, value,
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600643 loc_hex, loc_col1_indent,
644 loc_col1_width,
Michael Walshd995cb02017-02-07 14:46:01 -0600645 loc_trailing_char)
646 else:
647 buffer += sprint_varx(var_name + "[" + key + "]", value,
648 hex, loc_col1_indent, loc_col1_width,
649 loc_trailing_char)
Michael Walsh7423c012016-10-04 10:27:21 -0500650 elif type(var_value) in (list, tuple, set):
Michael Walshde791732016-09-06 14:25:24 -0500651 for key, value in enumerate(var_value):
Michael Walsh7423c012016-10-04 10:27:21 -0500652 ix += 1
653 if ix == length:
654 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -0500655 buffer += sprint_varx(var_name + "[" + str(key) + "]", value,
Michael Walsh7423c012016-10-04 10:27:21 -0500656 hex, loc_col1_indent, loc_col1_width,
657 loc_trailing_char)
Michael Walshde791732016-09-06 14:25:24 -0500658 elif type(var_value) is argparse.Namespace:
659 for key in var_value.__dict__:
Michael Walsh7423c012016-10-04 10:27:21 -0500660 ix += 1
661 if ix == length:
662 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -0500663 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \
Michael Walsh7423c012016-10-04 10:27:21 -0500664 + ", var_value." + key + ", hex, loc_col1_indent," \
665 + " loc_col1_width, loc_trailing_char)"
Michael Walshde791732016-09-06 14:25:24 -0500666 exec(cmd_buf)
667 else:
668 var_type = type(var_value).__name__
669 func_name = sys._getframe().f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -0500670 var_value = "<" + var_type + " type not supported by " + \
671 func_name + "()>"
Michael Walshde791732016-09-06 14:25:24 -0500672 value_format = "%s"
673 loc_col1_indent -= 2
Michael Walsh7423c012016-10-04 10:27:21 -0500674 # Adjust loc_col1_width.
675 loc_col1_width = loc_col1_width - loc_col1_indent
Michael Walshde791732016-09-06 14:25:24 -0500676 format_string = "%" + str(loc_col1_indent) + "s%-" \
Michael Walsh7423c012016-10-04 10:27:21 -0500677 + str(loc_col1_width) + "s" + value_format + trailing_char
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600678 return format_string % ("", str(var_name) + ":", var_value)
Michael Walsh23e7f492017-01-10 11:34:47 -0600679
Michael Walshde791732016-09-06 14:25:24 -0500680 return buffer
681
682 return ""
683
684###############################################################################
685
686
687###############################################################################
688def sprint_var(*args):
689
690 r"""
691 Figure out the name of the first argument for you and then call
692 sprint_varx with it. Therefore, the following 2 calls are equivalent:
693 sprint_varx("var1", var1)
694 sprint_var(var1)
695 """
696
697 # Get the name of the first variable passed to this function.
698 stack_frame = 2
Michael Walsh7423c012016-10-04 10:27:21 -0500699 caller_func_name = sprint_func_name(2)
700 if caller_func_name.endswith("print_var"):
Michael Walshde791732016-09-06 14:25:24 -0500701 stack_frame += 1
702 var_name = get_arg_name(None, 1, stack_frame)
703 return sprint_varx(var_name, *args)
704
705###############################################################################
706
707
708###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600709def sprint_vars(*args):
710
711 r"""
712 Sprint the values of one or more variables.
713
714 Description of args:
715 args:
716 If the first argument is an integer, it will be interpreted to be the
717 "indent" value.
718 If the second argument is an integer, it will be interpreted to be the
719 "col1_width" value.
720 If the third argument is an integer, it will be interpreted to be the
721 "hex" value.
722 All remaining parms are considered variable names which are to be
723 sprinted.
724 """
725
726 if len(args) == 0:
727 return
728
729 # Get the name of the first variable passed to this function.
730 stack_frame = 2
731 caller_func_name = sprint_func_name(2)
732 if caller_func_name.endswith("print_vars"):
733 stack_frame += 1
734
735 parm_num = 1
736
737 # Create list from args (which is a tuple) so that it can be modified.
738 args_list = list(args)
739
740 var_name = get_arg_name(None, parm_num, stack_frame)
741 # See if parm 1 is to be interpreted as "indent".
742 try:
743 if type(int(var_name)) is int:
744 indent = int(var_name)
745 args_list.pop(0)
746 parm_num += 1
747 except ValueError:
748 indent = 0
749
750 var_name = get_arg_name(None, parm_num, stack_frame)
751 # See if parm 1 is to be interpreted as "col1_width".
752 try:
753 if type(int(var_name)) is int:
754 loc_col1_width = int(var_name)
755 args_list.pop(0)
756 parm_num += 1
757 except ValueError:
758 loc_col1_width = col1_width
759
760 var_name = get_arg_name(None, parm_num, stack_frame)
761 # See if parm 1 is to be interpreted as "hex".
762 try:
763 if type(int(var_name)) is int:
764 hex = int(var_name)
765 args_list.pop(0)
766 parm_num += 1
767 except ValueError:
768 hex = 0
769
770 buffer = ""
771 for var_value in args_list:
772 var_name = get_arg_name(None, parm_num, stack_frame)
773 buffer += sprint_varx(var_name, var_value, hex, indent, loc_col1_width)
774 parm_num += 1
775
776 return buffer
777
778###############################################################################
779
780
781###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500782def lprint_varx(var_name,
783 var_value,
784 hex=0,
785 loc_col1_indent=col1_indent,
786 loc_col1_width=col1_width,
787 log_level=getattr(logging, 'INFO')):
788
789 r"""
790 Send sprint_varx output to logging.
791 """
792
793 logging.log(log_level, sprint_varx(var_name, var_value, hex,
794 loc_col1_indent, loc_col1_width, ""))
795
796###############################################################################
797
798
799###############################################################################
800def lprint_var(*args):
801
802 r"""
803 Figure out the name of the first argument for you and then call
804 lprint_varx with it. Therefore, the following 2 calls are equivalent:
805 lprint_varx("var1", var1)
806 lprint_var(var1)
807 """
808
809 # Get the name of the first variable passed to this function.
810 stack_frame = 2
811 caller_func_name = sprint_func_name(2)
812 if caller_func_name.endswith("print_var"):
813 stack_frame += 1
814 var_name = get_arg_name(None, 1, stack_frame)
815 lprint_varx(var_name, *args)
816
817###############################################################################
818
819
820###############################################################################
821def sprint_dashes(indent=col1_indent,
822 width=80,
823 line_feed=1,
824 char="-"):
Michael Walshde791732016-09-06 14:25:24 -0500825
826 r"""
827 Return a string of dashes to the caller.
828
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600829 Description of arguments:
Michael Walshde791732016-09-06 14:25:24 -0500830 indent The number of characters to indent the
831 output.
832 width The width of the string of dashes.
833 line_feed Indicates whether the output should end
834 with a line feed.
Michael Walsh7423c012016-10-04 10:27:21 -0500835 char The character to be repeated in the output
836 string.
Michael Walshde791732016-09-06 14:25:24 -0500837 """
838
Michael Walsh7423c012016-10-04 10:27:21 -0500839 width = int(width)
Michael Walsh23e7f492017-01-10 11:34:47 -0600840 buffer = " " * int(indent) + char * width
Michael Walshde791732016-09-06 14:25:24 -0500841 if line_feed:
842 buffer += "\n"
843
844 return buffer
845
846###############################################################################
847
848
849###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500850def sindent(text="",
851 indent=0):
852
853 r"""
854 Pre-pend the specified number of characters to the text string (i.e.
855 indent it) and return it.
856
857 Description of arguments:
858 text The string to be indented.
859 indent The number of characters to indent the
860 string.
861 """
862
863 format_string = "%" + str(indent) + "s%s"
864 buffer = format_string % ("", text)
865
866 return buffer
867
868###############################################################################
869
870
871###############################################################################
872def sprint_call_stack(indent=0,
873 stack_frame_ix=0):
Michael Walshde791732016-09-06 14:25:24 -0500874
875 r"""
876 Return a call stack report for the given point in the program with line
877 numbers, function names and function parameters and arguments.
878
879 Sample output:
880
881 -------------------------------------------------------------------------
882 Python function call stack
883
884 Line # Function name and arguments
885 ------ ------------------------------------------------------------------
886 424 sprint_call_stack ()
887 4 print_call_stack ()
888 31 func1 (last_name = 'walsh', first_name = 'mikey')
889 59 /tmp/scr5.py
890 -------------------------------------------------------------------------
891
892 Description of arguments:
893 indent The number of characters to indent each
894 line of output.
895 stack_frame_ix The index of the first stack frame which
896 is to be returned.
897 """
898
899 buffer = ""
Michael Walsh7423c012016-10-04 10:27:21 -0500900 buffer += sprint_dashes(indent)
901 buffer += sindent("Python function call stack\n\n", indent)
902 buffer += sindent("Line # Function name and arguments\n", indent)
903 buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73)
Michael Walshde791732016-09-06 14:25:24 -0500904
905 # Grab the current program stack.
906 current_stack = inspect.stack()
907
908 # Process each frame in turn.
909 format_string = "%6s %s\n"
Michael Walsh7423c012016-10-04 10:27:21 -0500910 ix = 0
Michael Walshde791732016-09-06 14:25:24 -0500911 for stack_frame in current_stack:
Michael Walsh7423c012016-10-04 10:27:21 -0500912 if ix < stack_frame_ix:
913 ix += 1
914 continue
Michael Walsh23e7f492017-01-10 11:34:47 -0600915 # I want the line number shown to be the line where you find the line
916 # shown.
917 try:
918 line_num = str(current_stack[ix + 1][2])
919 except IndexError:
920 line_num = ""
Michael Walshde791732016-09-06 14:25:24 -0500921 func_name = str(stack_frame[3])
922 if func_name == "?":
923 # "?" is the name used when code is not in a function.
924 func_name = "(none)"
925
926 if func_name == "<module>":
Michael Walsh7423c012016-10-04 10:27:21 -0500927 # If the func_name is the "main" program, we simply get the
928 # command line call string.
Michael Walshde791732016-09-06 14:25:24 -0500929 func_and_args = ' '.join(sys.argv)
930 else:
931 # Get the program arguments.
932 arg_vals = inspect.getargvalues(stack_frame[0])
933 function_parms = arg_vals[0]
934 frame_locals = arg_vals[3]
935
Michael Walsh7423c012016-10-04 10:27:21 -0500936 args_list = []
Michael Walshde791732016-09-06 14:25:24 -0500937 for arg_name in function_parms:
938 # Get the arg value from frame locals.
939 arg_value = frame_locals[arg_name]
Michael Walsh7423c012016-10-04 10:27:21 -0500940 args_list.append(arg_name + " = " + repr(arg_value))
941 args_str = "(" + ', '.join(map(str, args_list)) + ")"
Michael Walshde791732016-09-06 14:25:24 -0500942
943 # Now we need to print this in a nicely-wrapped way.
944 func_and_args = func_name + " " + args_str
945
Michael Walsh23e7f492017-01-10 11:34:47 -0600946 buffer += sindent(format_string % (line_num, func_and_args), indent)
Michael Walsh7423c012016-10-04 10:27:21 -0500947 ix += 1
Michael Walshde791732016-09-06 14:25:24 -0500948
Michael Walsh7423c012016-10-04 10:27:21 -0500949 buffer += sprint_dashes(indent)
Michael Walshde791732016-09-06 14:25:24 -0500950
951 return buffer
952
953###############################################################################
954
955
956###############################################################################
957def sprint_executing(stack_frame_ix=None):
958
959 r"""
960 Print a line indicating what function is executing and with what parameter
961 values. This is useful for debugging.
962
963 Sample output:
964
965 #(CDT) 2016/08/25 17:54:27 - Executing: func1 (x = 1)
966
967 Description of arguments:
968 stack_frame_ix The index of the stack frame whose
969 function info should be returned. If the
Michael Walsh2ee77cd2017-03-08 11:50:17 -0600970 caller does not specify a value, this
Michael Walshde791732016-09-06 14:25:24 -0500971 function will set the value to 1 which is
972 the index of the caller's stack frame. If
973 the caller is the wrapper function
974 "print_executing", this function will bump
975 it up by 1.
976 """
977
978 # If user wants default stack_frame_ix.
979 if stack_frame_ix is None:
980 func_name = sys._getframe().f_code.co_name
981 caller_func_name = sys._getframe(1).f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -0500982 if caller_func_name.endswith(func_name[1:]):
Michael Walshde791732016-09-06 14:25:24 -0500983 stack_frame_ix = 2
984 else:
985 stack_frame_ix = 1
986
987 stack_frame = inspect.stack()[stack_frame_ix]
988
989 func_name = str(stack_frame[3])
990 if func_name == "?":
991 # "?" is the name used when code is not in a function.
992 func_name = "(none)"
993
994 if func_name == "<module>":
995 # If the func_name is the "main" program, we simply get the command
996 # line call string.
997 func_and_args = ' '.join(sys.argv)
998 else:
999 # Get the program arguments.
1000 arg_vals = inspect.getargvalues(stack_frame[0])
1001 function_parms = arg_vals[0]
1002 frame_locals = arg_vals[3]
1003
Michael Walsh7423c012016-10-04 10:27:21 -05001004 args_list = []
Michael Walshde791732016-09-06 14:25:24 -05001005 for arg_name in function_parms:
1006 # Get the arg value from frame locals.
1007 arg_value = frame_locals[arg_name]
Michael Walsh7423c012016-10-04 10:27:21 -05001008 args_list.append(arg_name + " = " + repr(arg_value))
1009 args_str = "(" + ', '.join(map(str, args_list)) + ")"
Michael Walshde791732016-09-06 14:25:24 -05001010
1011 # Now we need to print this in a nicely-wrapped way.
1012 func_and_args = func_name + " " + args_str
1013
1014 return sprint_time() + "Executing: " + func_and_args + "\n"
1015
1016###############################################################################
1017
1018
1019###############################################################################
Michael Walshbec416d2016-11-10 08:54:52 -06001020def sprint_pgm_header(indent=0,
1021 linefeed=1):
Michael Walshde791732016-09-06 14:25:24 -05001022
1023 r"""
1024 Return a standardized header that programs should print at the beginning
1025 of the run. It includes useful information like command line, pid,
1026 userid, program parameters, etc.
1027
Michael Walsh7423c012016-10-04 10:27:21 -05001028 Description of arguments:
1029 indent The number of characters to indent each
1030 line of output.
Michael Walshbec416d2016-11-10 08:54:52 -06001031 linefeed Indicates whether a line feed be included
1032 at the beginning and end of the report.
Michael Walshde791732016-09-06 14:25:24 -05001033 """
1034
Michael Walshbec416d2016-11-10 08:54:52 -06001035 loc_col1_width = col1_width + indent
1036
1037 buffer = ""
1038 if linefeed:
1039 buffer = "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001040
1041 buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent)
1042 buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n",
1043 indent)
Michael Walshbec416d2016-11-10 08:54:52 -06001044 buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent,
1045 loc_col1_width)
Michael Walsh7423c012016-10-04 10:27:21 -05001046 # We want the output to show a customized name for the pid and pgid but
1047 # we want it to look like a valid variable name. Therefore, we'll use
Michael Walshde791732016-09-06 14:25:24 -05001048 # pgm_name_var_name which was set when this module was imported.
Michael Walshbec416d2016-11-10 08:54:52 -06001049 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent,
1050 loc_col1_width)
1051 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent,
1052 loc_col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001053 userid_num = str(os.geteuid())
1054 try:
1055 username = os.getlogin()
1056 except OSError:
1057 if userid_num == "0":
1058 username = "root"
1059 else:
1060 username = "?"
1061 buffer += sprint_varx("uid", userid_num + " (" + username +
Michael Walshbec416d2016-11-10 08:54:52 -06001062 ")", 0, indent, loc_col1_width)
Michael Walshde791732016-09-06 14:25:24 -05001063 buffer += sprint_varx("gid", str(os.getgid()) + " (" +
Michael Walsh7423c012016-10-04 10:27:21 -05001064 str(grp.getgrgid(os.getgid()).gr_name) + ")", 0,
Michael Walshbec416d2016-11-10 08:54:52 -06001065 indent, loc_col1_width)
1066 buffer += sprint_varx("host_name", socket.gethostname(), 0, indent,
1067 loc_col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001068 try:
1069 DISPLAY = os.environ['DISPLAY']
1070 except KeyError:
1071 DISPLAY = ""
1072 buffer += sprint_varx("DISPLAY", DISPLAY, 0, indent,
Michael Walshbec416d2016-11-10 08:54:52 -06001073 loc_col1_width)
Michael Walshde791732016-09-06 14:25:24 -05001074 # I want to add code to print caller's parms.
1075
Michael Walsh7423c012016-10-04 10:27:21 -05001076 # __builtin__.arg_obj is created by the get_arg module function,
1077 # gen_get_options.
1078 try:
1079 buffer += ga.sprint_args(__builtin__.arg_obj, indent)
1080 except AttributeError:
1081 pass
1082
Michael Walshbec416d2016-11-10 08:54:52 -06001083 if linefeed:
1084 buffer += "\n"
Michael Walshde791732016-09-06 14:25:24 -05001085
1086 return buffer
1087
1088###############################################################################
1089
1090
1091###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -05001092def sprint_error_report(error_text="\n",
1093 indent=2):
1094
1095 r"""
1096 Return a string with a standardized report which includes the caller's
1097 error text, the call stack and the program header.
1098
1099 Description of args:
1100 error_text The error text to be included in the
1101 report. The caller should include any
1102 needed linefeeds.
1103 indent The number of characters to indent each
1104 line of output.
1105 """
1106
1107 buffer = ""
1108 buffer += sprint_dashes(width=120, char="=")
1109 buffer += sprint_error(error_text)
1110 buffer += "\n"
1111 # Calling sprint_call_stack with stack_frame_ix of 0 causes it to show
1112 # itself and this function in the call stack. This is not helpful to a
1113 # debugger and is therefore clutter. We will adjust the stack_frame_ix to
1114 # hide that information.
1115 stack_frame_ix = 2
1116 caller_func_name = sprint_func_name(2)
1117 if caller_func_name.endswith("print_error_report"):
1118 stack_frame_ix += 1
1119 buffer += sprint_call_stack(indent, stack_frame_ix)
1120 buffer += sprint_pgm_header(indent)
1121 buffer += sprint_dashes(width=120, char="=")
1122
1123 return buffer
1124
1125###############################################################################
1126
1127
1128###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -06001129def sprint_issuing(cmd_buf,
1130 test_mode=0):
Michael Walshde791732016-09-06 14:25:24 -05001131
1132 r"""
1133 Return a line indicating a command that the program is about to execute.
1134
1135 Sample output for a cmd_buf of "ls"
1136
1137 #(CDT) 2016/08/25 17:57:36 - Issuing: ls
Michael Walshbec416d2016-11-10 08:54:52 -06001138
Michael Walshde791732016-09-06 14:25:24 -05001139 Description of args:
1140 cmd_buf The command to be executed by caller.
Michael Walshbec416d2016-11-10 08:54:52 -06001141 test_mode With test_mode set, your output will look
1142 like this:
1143
1144 #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls
1145
Michael Walshde791732016-09-06 14:25:24 -05001146 """
1147
Michael Walshbec416d2016-11-10 08:54:52 -06001148 buffer = sprint_time()
1149 if test_mode:
1150 buffer += "(test_mode) "
1151 buffer += "Issuing: " + cmd_buf + "\n"
Michael Walshde791732016-09-06 14:25:24 -05001152
1153 return buffer
1154
1155###############################################################################
1156
1157
1158###############################################################################
1159def sprint_pgm_footer():
1160
1161 r"""
1162 Return a standardized footer that programs should print at the end of the
1163 program run. It includes useful information like total run time, etc.
1164 """
1165
1166 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n"
1167
1168 total_time = time.time() - start_time
1169 total_time_string = "%0.6f" % total_time
1170
Michael Walsh7423c012016-10-04 10:27:21 -05001171 buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string)
Michael Walshbec416d2016-11-10 08:54:52 -06001172 buffer += "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001173
1174 return buffer
1175
1176###############################################################################
1177
1178
1179###############################################################################
1180def sprint(buffer=""):
1181
1182 r"""
1183 Simply return the user's buffer. This function is used by the qprint and
1184 dprint functions defined dynamically below, i.e. it would not normally be
1185 called for general use.
1186
1187 Description of arguments.
1188 buffer This will be returned to the caller.
1189 """
Michael Walshde791732016-09-06 14:25:24 -05001190
Michael Walshbec416d2016-11-10 08:54:52 -06001191 return str(buffer)
1192
1193###############################################################################
1194
1195
1196###############################################################################
1197def sprintn(buffer=""):
1198
1199 r"""
1200 Simply return the user's buffer with a line feed. This function is used
1201 by the qprint and dprint functions defined dynamically below, i.e. it
1202 would not normally be called for general use.
1203
1204 Description of arguments.
1205 buffer This will be returned to the caller.
1206 """
1207
1208 buffer = str(buffer) + "\n"
1209
Michael Walshde791732016-09-06 14:25:24 -05001210 return buffer
1211
1212###############################################################################
1213
1214
1215###############################################################################
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001216def gp_debug_print(buffer):
1217
1218 r"""
1219 Print buffer to stdout only if gen_print_debug is set.
1220
1221 This function is intended for use only by other functions in this module.
1222
1223 Description of arguments:
1224 buffer The string to be printed.
1225 """
1226
1227 if not gen_print_debug:
1228 return
1229
1230 if robot_env:
1231 BuiltIn().log_to_console(buffer)
1232 else:
1233 print(buffer)
1234
1235###############################################################################
1236
1237
1238###############################################################################
1239def gp_get_var_value(var_name,
1240 default=1):
1241
1242 r"""
1243 Get the value of the named variable and return it. If the variable is not
1244 defined, the default value is returned.
1245
1246 If we are in a robot environment, get_variable_value will be used.
1247 Otherwise, the __builtin__ version of the variable is returned.
1248
1249 This function is intended for use only by other functions in this module.
1250
1251 Description of arguments:
1252 var_name The name of the variable whose value is to
1253 be returned.
1254 default The value that is returned if var_name is
1255 not defined.
1256 """
1257
1258 if robot_env:
1259 var_value = int(BuiltIn().get_variable_value("${" + var_name + "}",
1260 default))
1261 else:
1262 var_value = getattr(__builtin__, var_name, default)
1263
1264 return var_value
1265
1266###############################################################################
1267
1268
1269###############################################################################
Michael Walshde791732016-09-06 14:25:24 -05001270# In the following section of code, we will dynamically create print versions
1271# for each of the sprint functions defined above. So, for example, where we
1272# have an sprint_time() function defined above that returns the time to the
Michael Walsh7423c012016-10-04 10:27:21 -05001273# caller in a string, we will create a corresponding print_time() function
1274# that will print that string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -05001275
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001276# It can be complicated to follow what's being created by the exec statements
Michael Walshde791732016-09-06 14:25:24 -05001277# below. Here is an example of the print_time() function that will be created:
1278
1279# def print_time(*args):
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001280# s_func = getattr(sys.modules[__name__], "sprint_time")
1281# sys.stdout.write(s_func(*args))
1282# sys.stdout.flush()
Michael Walshde791732016-09-06 14:25:24 -05001283
1284# Here are comments describing the 3 lines in the body of the created function.
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001285# Create a reference to the "s" version of the given function in s_func (e.g.
1286# if this function name is print_time, we want s_funcname to be "sprint_time").
Michael Walsh7423c012016-10-04 10:27:21 -05001287# Call the "s" version of this function passing it all of our arguments.
1288# Write the result to stdout.
Michael Walshde791732016-09-06 14:25:24 -05001289
1290# func_names contains a list of all print functions which should be created
1291# from their sprint counterparts.
1292func_names = ['print_time', 'print_timen', 'print_error', 'print_varx',
Michael Walsh18176322016-11-15 15:11:21 -06001293 'print_var', 'print_vars', 'print_dashes', 'indent',
1294 'print_call_stack', 'print_func_name', 'print_executing',
1295 'print_pgm_header', 'print_issuing', 'print_pgm_footer',
1296 'print_error_report', 'print', 'printn']
Michael Walshde791732016-09-06 14:25:24 -05001297
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001298# stderr_func_names is a list of functions whose output should go to stderr
1299# rather than stdout.
1300stderr_func_names = ['print_error', 'print_error_report']
Michael Walshde791732016-09-06 14:25:24 -05001301
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001302gp_debug_print("robot_env: " + str(robot_env))
Michael Walshde791732016-09-06 14:25:24 -05001303for func_name in func_names:
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001304 gp_debug_print("func_name: " + func_name)
1305 if func_name in stderr_func_names:
Michael Walshde791732016-09-06 14:25:24 -05001306 output_stream = "stderr"
1307 else:
1308 output_stream = "stdout"
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001309
1310 func_def_line = "def " + func_name + "(*args):"
1311 s_func_line = " s_func = getattr(sys.modules[__name__], \"s" +\
1312 func_name + "\")"
1313 # Generate the code to do the printing.
1314 if robot_env:
1315 func_print_lines = \
1316 [
1317 " BuiltIn().log_to_console(s_func(*args),"
1318 " stream='" + output_stream + "',"
1319 " no_newline=True)"
1320 ]
1321 else:
1322 func_print_lines = \
1323 [
1324 " sys." + output_stream + ".write(s_func(*args))",
1325 " sys." + output_stream + ".flush()"
1326 ]
1327
1328 # Create an array containing the lines of the function we wish to create.
1329 func_def = [func_def_line, s_func_line] + func_print_lines
1330 # We don't want to try to redefine the "print" function, thus the if
1331 # statement.
Michael Walsh7423c012016-10-04 10:27:21 -05001332 if func_name != "print":
1333 pgm_definition_string = '\n'.join(func_def)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001334 gp_debug_print(pgm_definition_string)
Michael Walsh7423c012016-10-04 10:27:21 -05001335 exec(pgm_definition_string)
1336
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001337 # Insert a blank line which will be overwritten by the next several
1338 # definitions.
1339 func_def.insert(1, "")
Michael Walsh7423c012016-10-04 10:27:21 -05001340
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001341 # Define the "q" (i.e. quiet) version of the given print function.
1342 func_def[0] = "def q" + func_name + "(*args):"
1343 func_def[1] = " if gp_get_var_value(\"quiet\", 0): return"
Michael Walshde791732016-09-06 14:25:24 -05001344 pgm_definition_string = '\n'.join(func_def)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001345 gp_debug_print(pgm_definition_string)
Michael Walshde791732016-09-06 14:25:24 -05001346 exec(pgm_definition_string)
1347
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001348 # Define the "d" (i.e. debug) version of the given print function.
1349 func_def[0] = "def d" + func_name + "(*args):"
1350 func_def[1] = " if not gp_get_var_value(\"debug\", 0): return"
Michael Walsh7423c012016-10-04 10:27:21 -05001351 pgm_definition_string = '\n'.join(func_def)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001352 gp_debug_print(pgm_definition_string)
Michael Walsh7423c012016-10-04 10:27:21 -05001353 exec(pgm_definition_string)
1354
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001355 # Define the "l" (i.e. log) version of the given print function.
1356 func_def_line = "def l" + func_name + "(*args):"
1357 func_print_lines = \
Michael Walsh7423c012016-10-04 10:27:21 -05001358 [
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001359 " logging.log(getattr(logging, 'INFO'), s_func(*args))"
Michael Walsh7423c012016-10-04 10:27:21 -05001360 ]
1361
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001362 func_def = [func_def_line, s_func_line] + func_print_lines
Michael Walsh7423c012016-10-04 10:27:21 -05001363 if func_name != "print_varx" and func_name != "print_var":
1364 pgm_definition_string = '\n'.join(func_def)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001365 gp_debug_print(pgm_definition_string)
Michael Walsh7423c012016-10-04 10:27:21 -05001366 exec(pgm_definition_string)
1367
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001368 if func_name == "print" or func_name == "printn":
1369 gp_debug_print("")
Michael Walsh7423c012016-10-04 10:27:21 -05001370 continue
1371
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001372 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var).
Michael Walshde791732016-09-06 14:25:24 -05001373 alias = re.sub("print_", "p", func_name)
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001374 prefixes = ["", "s", "q", "d", "l"]
1375 for prefix in prefixes:
1376 pgm_definition_string = prefix + alias + " = " + prefix + func_name
1377 gp_debug_print(pgm_definition_string)
1378 exec(pgm_definition_string)
Michael Walsh7423c012016-10-04 10:27:21 -05001379
Michael Walsh2ee77cd2017-03-08 11:50:17 -06001380 gp_debug_print("")
Michael Walshde791732016-09-06 14:25:24 -05001381
1382###############################################################################