blob: 643a3bea7b7dc9772a12497ee7b9e8e3c5e24f6f [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:
21 from robot.utils import DotDict
Michael Walsh8e6deb42017-01-27 14:22:41 -060022 from robot.utils import NormalizedDict
Michael Walshbec416d2016-11-10 08:54:52 -060023except ImportError:
Michael Walsha6723f22016-11-22 11:12:01 -060024 pass
Michael Walsh7423c012016-10-04 10:27:21 -050025
26import gen_arg as ga
Michael Walshde791732016-09-06 14:25:24 -050027
28# Setting these variables for use both inside this module and by programs
29# importing this module.
30pgm_dir_path = sys.argv[0]
31pgm_name = os.path.basename(pgm_dir_path)
Michael Walsh7423c012016-10-04 10:27:21 -050032pgm_dir_name = re.sub("/" + pgm_name, "", pgm_dir_path) + "/"
33
Michael Walshde791732016-09-06 14:25:24 -050034
35# Some functions (e.g. sprint_pgm_header) have need of a program name value
36# that looks more like a valid variable name. Therefore, we'll swap odd
37# characters like "." out for underscores.
38pgm_name_var_name = pgm_name.replace(".", "_")
39
40# Initialize global values used as defaults by print_time, print_var, etc.
41col1_indent = 0
42
43# Calculate default column width for print_var functions based on environment
44# variable settings. The objective is to make the variable values line up
45# nicely with the time stamps.
46col1_width = 29
47if 'NANOSECONDS' in os.environ:
48 NANOSECONDS = os.environ['NANOSECONDS']
49else:
50 NANOSECONDS = 0
51
52if NANOSECONDS == "1":
53 col1_width = col1_width + 7
54
55if 'SHOW_ELAPSED_TIME' in os.environ:
56 SHOW_ELAPSED_TIME = os.environ['SHOW_ELAPSED_TIME']
57else:
58 SHOW_ELAPSED_TIME = 0
59
60if SHOW_ELAPSED_TIME == "1":
61 if NANOSECONDS == "1":
62 col1_width = col1_width + 14
63 else:
64 col1_width = col1_width + 7
65
66# Initialize some time variables used in module functions.
67start_time = time.time()
68sprint_time_last_seconds = start_time
69
Michael Walsh7423c012016-10-04 10:27:21 -050070try:
71 # The user can set environment variable "GEN_PRINT_DEBUG" to get debug
72 # output from this module.
Michael Walsha6723f22016-11-22 11:12:01 -060073 gen_print_debug = int(os.environ['GEN_PRINT_DEBUG'])
Michael Walsh7423c012016-10-04 10:27:21 -050074except KeyError:
75 gen_print_debug = 0
76
Michael Walshde791732016-09-06 14:25:24 -050077
78###############################################################################
79def sprint_func_name(stack_frame_ix=None):
80
81 r"""
82 Return the function name associated with the indicated stack frame.
83
84 Description of arguments:
85 stack_frame_ix The index of the stack frame whose
86 function name should be returned. If the
87 caller does not specifiy a value, this
88 function will set the value to 1 which is
89 the index of the caller's stack frame. If
90 the caller is the wrapper function
91 "print_func_name", this function will bump
92 it up by 1.
93 """
94
95 # If user specified no stack_frame_ix, we'll set it to a proper default
96 # value.
97 if stack_frame_ix is None:
98 func_name = sys._getframe().f_code.co_name
99 caller_func_name = sys._getframe(1).f_code.co_name
100 if func_name[1:] == caller_func_name:
101 stack_frame_ix = 2
102 else:
103 stack_frame_ix = 1
104
105 func_name = sys._getframe(stack_frame_ix).f_code.co_name
106
107 return func_name
108
109###############################################################################
110
111
112# get_arg_name is not a print function per se. I have included it in this
113# module because it is used by sprint_var which is found in this module.
114###############################################################################
115def get_arg_name(var,
116 arg_num=1,
117 stack_frame_ix=1):
118
119 r"""
120 Return the "name" of an argument passed to a function. This could be a
121 literal or a variable name.
122
123 Description of arguements:
124 var The variable whose name you want returned.
125 arg_num The arg number (1 through n) whose name
126 you wish to have returned. This value
127 should not exceed the number of arguments
128 allowed by the target function.
129 stack_frame_ix The stack frame index of the target
130 function. This value must be 1 or
131 greater. 1 would indicate get_arg_name's
132 stack frame. 2 would be the caller of
133 get_arg_name's stack frame, etc.
134
135 Example 1:
136
137 my_var = "mike"
138 var_name = get_arg_name(my_var)
139
140 In this example, var_name will receive the value "my_var".
141
142 Example 2:
143
144 def test1(var):
145 # Getting the var name of the first arg to this function, test1.
146 # Note, in this case, it doesn't matter what you pass as the first arg
147 # to get_arg_name since it is the caller's variable name that matters.
148 dummy = 1
149 arg_num = 1
150 stack_frame = 2
151 var_name = get_arg_name(dummy, arg_num, stack_frame)
152
153 # Mainline...
154
155 another_var = "whatever"
156 test1(another_var)
157
158 In this example, var_name will be set to "another_var".
159
160 """
161
162 # Note: I wish to avoid recursion so I refrain from calling any function
163 # that calls this function (i.e. sprint_var, valid_value, etc.).
164
Michael Walsh23e7f492017-01-10 11:34:47 -0600165 # The user can set environment variable "GET_ARG_NAME_DEBUG" to get debug
166 # output from this function.
167 local_debug = int(os.environ.get('GET_ARG_NAME_DEBUG', 0))
168 # In addition to GET_ARG_NAME_DEBUG, the user can set environment
169 # variable "GET_ARG_NAME_SHOW_SOURCE" to have this function include source
170 # code in the debug output.
171 local_debug_show_source = int(
172 os.environ.get('GET_ARG_NAME_SHOW_SOURCE', 0))
Michael Walshde791732016-09-06 14:25:24 -0500173
174 if arg_num < 1:
175 print_error("Programmer error - Variable \"arg_num\" has an invalid" +
176 " value of \"" + str(arg_num) + "\". The value must be" +
177 " an integer that is greater than 0.\n")
178 # What is the best way to handle errors? Raise exception? I'll
179 # revisit later.
180 return
181 if stack_frame_ix < 1:
182 print_error("Programmer error - Variable \"stack_frame_ix\" has an" +
183 " invalid value of \"" + str(stack_frame_ix) + "\". The" +
184 " value must be an integer that is greater than or equal" +
185 " to 1.\n")
186 return
187
188 if local_debug:
189 debug_indent = 2
Michael Walsh23e7f492017-01-10 11:34:47 -0600190 print("")
191 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500192 print(sprint_func_name() + "() parms:")
193 print_varx("var", var, 0, debug_indent)
194 print_varx("arg_num", arg_num, 0, debug_indent)
195 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600196 print("")
197 print_call_stack(debug_indent, 2)
Michael Walshde791732016-09-06 14:25:24 -0500198
Michael Walsh23e7f492017-01-10 11:34:47 -0600199 for count in range(0, 2):
200 try:
201 frame, filename, cur_line_no, function_name, lines, index = \
202 inspect.stack()[stack_frame_ix]
203 except IndexError:
204 print_error("Programmer error - The caller has asked for" +
205 " information about the stack frame at index \"" +
206 str(stack_frame_ix) + "\". However, the stack" +
207 " only contains " + str(len(inspect.stack())) +
208 " entries. Therefore the stack frame index is out" +
209 " of range.\n")
210 return
211 if filename != "<string>":
212 break
213 # filename of "<string>" may mean that the function in question was
214 # defined dynamically and therefore its code stack is inaccessible.
215 # This may happen with functions like "rqprint_var". In this case,
216 # we'll increment the stack_frame_ix and try again.
217 stack_frame_ix += 1
218 if local_debug:
219 print("Adjusted stack_frame_ix...")
220 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500221
222 called_func_name = sprint_func_name(stack_frame_ix)
Michael Walsh23e7f492017-01-10 11:34:47 -0600223
224 module = inspect.getmodule(frame)
225
226 # Though I would expect inspect.getsourcelines(frame) to get all module
227 # source lines if the frame is "<module>", it doesn't do that. Therefore,
228 # for this special case, I will do inspect.getsourcelines(module).
229 if function_name == "<module>":
230 source_lines, source_line_num =\
231 inspect.getsourcelines(module)
232 line_ix = cur_line_no - source_line_num - 1
233 else:
234 source_lines, source_line_num =\
235 inspect.getsourcelines(frame)
236 line_ix = cur_line_no - source_line_num
237
238 if local_debug:
239 print("\n Variables retrieved from inspect.stack() function:")
240 print_varx("frame", frame, 0, debug_indent + 2)
241 print_varx("filename", filename, 0, debug_indent + 2)
242 print_varx("cur_line_no", cur_line_no, 0, debug_indent + 2)
243 print_varx("function_name", function_name, 0, debug_indent + 2)
244 print_varx("lines", lines, 0, debug_indent + 2)
245 print_varx("index", index, 0, debug_indent + 2)
246 print_varx("source_line_num", source_line_num, 0, debug_indent)
247 print_varx("line_ix", line_ix, 0, debug_indent)
248 if local_debug_show_source:
249 print_varx("source_lines", source_lines, 0, debug_indent)
250 print_varx("called_func_name", called_func_name, 0, debug_indent)
251
252 # Get a list of all functions defined for the module. Note that this
253 # doesn't work consistently when _run_exitfuncs is at the top of the stack
254 # (i.e. if we're running an exit function). I've coded a work-around
255 # below for this deficiency.
256 all_functions = inspect.getmembers(module, inspect.isfunction)
257
258 # Get called_func_id by searching for our function in the list of all
259 # functions.
260 called_func_id = None
261 for func_name, function in all_functions:
262 if func_name == called_func_name:
263 called_func_id = id(function)
264 break
265 # NOTE: The only time I've found that called_func_id can't be found is
266 # when we're running from an exit function.
267
268 # Look for other functions in module with matching id.
269 aliases = set([called_func_name])
270 for func_name, function in all_functions:
271 if func_name == called_func_name:
272 continue
273 func_id = id(function)
274 if func_id == called_func_id:
275 aliases.add(func_name)
276
277 # In most cases, my general purpose code above will find all aliases.
278 # However, for the odd case (i.e. running from exit function), I've added
279 # code to handle pvar, qpvar, dpvar, etc. aliases explicitly since they
280 # are defined in this module and used frequently.
281 # pvar is an alias for print_var.
282 aliases.add(re.sub("print_var", "pvar", called_func_name))
283
284 func_regex = ".*(" + '|'.join(aliases) + ")[ ]*\("
285
286 # Search backward through source lines looking for the calling function
287 # name.
288 found = False
289 for start_line_ix in range(line_ix, 0, -1):
290 # Skip comment lines.
291 if re.match(r"[ ]*#", source_lines[start_line_ix]):
292 continue
293 if re.match(func_regex, source_lines[start_line_ix]):
294 found = True
295 break
296 if not found:
297 print_error("Programmer error - Could not find the source line with" +
298 " a reference to function \"" + called_func_name + "\".\n")
299 return
300
301 # Search forward through the source lines looking for a line with the
302 # same indentation as the start time. The end of our composite line
303 # should be the line preceding that line.
304 start_indent = len(source_lines[start_line_ix]) -\
305 len(source_lines[start_line_ix].lstrip(' '))
306 end_line_ix = line_ix
307 for end_line_ix in range(line_ix + 1, len(source_lines)):
308 if source_lines[end_line_ix].strip() == "":
309 continue
310 line_indent = len(source_lines[end_line_ix]) -\
311 len(source_lines[end_line_ix].lstrip(' '))
312 if line_indent == start_indent:
313 end_line_ix -= 1
314 break
315
316 # Join the start line through the end line into a composite line.
317 composite_line = ''.join(map(str.strip,
318 source_lines[start_line_ix:end_line_ix + 1]))
Michael Walsh7423c012016-10-04 10:27:21 -0500319
Michael Walshbec416d2016-11-10 08:54:52 -0600320 # arg_list_etc = re.sub(".*" + called_func_name, "", composite_line)
321 arg_list_etc = "(" + re.sub(func_regex, "", composite_line)
Michael Walshde791732016-09-06 14:25:24 -0500322 if local_debug:
Michael Walsh23e7f492017-01-10 11:34:47 -0600323 print_varx("aliases", aliases, 0, debug_indent)
Michael Walshbec416d2016-11-10 08:54:52 -0600324 print_varx("func_regex", func_regex, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600325 print_varx("start_line_ix", start_line_ix, 0, debug_indent)
326 print_varx("end_line_ix", end_line_ix, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500327 print_varx("composite_line", composite_line, 0, debug_indent)
328 print_varx("arg_list_etc", arg_list_etc, 0, debug_indent)
329
330 # Parse arg list...
331 # Initialize...
332 nest_level = -1
333 arg_ix = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500334 args_list = [""]
Michael Walshde791732016-09-06 14:25:24 -0500335 for ix in range(0, len(arg_list_etc)):
336 char = arg_list_etc[ix]
337 # Set the nest_level based on whether we've encounted a parenthesis.
338 if char == "(":
339 nest_level += 1
340 if nest_level == 0:
341 continue
342 elif char == ")":
343 nest_level -= 1
344 if nest_level < 0:
345 break
346
347 # If we reach a comma at base nest level, we are done processing an
Michael Walsh7423c012016-10-04 10:27:21 -0500348 # argument so we increment arg_ix and initialize a new args_list entry.
Michael Walshde791732016-09-06 14:25:24 -0500349 if char == "," and nest_level == 0:
350 arg_ix += 1
Michael Walsh7423c012016-10-04 10:27:21 -0500351 args_list.append("")
Michael Walshde791732016-09-06 14:25:24 -0500352 continue
353
Michael Walsh7423c012016-10-04 10:27:21 -0500354 # For any other character, we append it it to the current arg list
Michael Walshde791732016-09-06 14:25:24 -0500355 # entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500356 args_list[arg_ix] += char
Michael Walshde791732016-09-06 14:25:24 -0500357
358 # Trim whitespace from each list entry.
Michael Walsh7423c012016-10-04 10:27:21 -0500359 args_list = [arg.strip() for arg in args_list]
Michael Walshde791732016-09-06 14:25:24 -0500360
Michael Walsh7423c012016-10-04 10:27:21 -0500361 if arg_num > len(args_list):
Michael Walshde791732016-09-06 14:25:24 -0500362 print_error("Programmer error - The caller has asked for the name of" +
363 " argument number \"" + str(arg_num) + "\" but there " +
Michael Walsh7423c012016-10-04 10:27:21 -0500364 "were only \"" + str(len(args_list)) + "\" args used:\n" +
365 sprint_varx("args_list", args_list))
Michael Walshde791732016-09-06 14:25:24 -0500366 return
367
Michael Walsh7423c012016-10-04 10:27:21 -0500368 argument = args_list[arg_num - 1]
Michael Walshde791732016-09-06 14:25:24 -0500369
370 if local_debug:
Michael Walsh7423c012016-10-04 10:27:21 -0500371 print_varx("args_list", args_list, 0, debug_indent)
Michael Walshde791732016-09-06 14:25:24 -0500372 print_varx("argument", argument, 0, debug_indent)
Michael Walsh23e7f492017-01-10 11:34:47 -0600373 print_dashes(0, 120)
Michael Walshde791732016-09-06 14:25:24 -0500374
375 return argument
376
377###############################################################################
378
379
380###############################################################################
381def sprint_time(buffer=""):
382
383 r"""
384 Return the time in the following format.
385
386 Example:
387
388 The following python code...
389
390 sys.stdout.write(sprint_time())
391 sys.stdout.write("Hi.\n")
392
393 Will result in the following type of output:
394
395 #(CDT) 2016/07/08 15:25:35 - Hi.
396
397 Example:
398
399 The following python code...
400
401 sys.stdout.write(sprint_time("Hi.\n"))
402
403 Will result in the following type of output:
404
405 #(CDT) 2016/08/03 17:12:05 - Hi.
406
407 The following environment variables will affect the formatting as
408 described:
409 NANOSECONDS This will cause the time stamps to be
410 precise to the microsecond (Yes, it
411 probably should have been named
412 MICROSECONDS but the convention was set
413 long ago so we're sticking with it).
414 Example of the output when environment
415 variable NANOSECONDS=1.
416
417 #(CDT) 2016/08/03 17:16:25.510469 - Hi.
418
419 SHOW_ELAPSED_TIME This will cause the elapsed time to be
420 included in the output. This is the
421 amount of time that has elapsed since the
422 last time this function was called. The
423 precision of the elapsed time field is
424 also affected by the value of the
425 NANOSECONDS environment variable. Example
426 of the output when environment variable
427 NANOSECONDS=0 and SHOW_ELAPSED_TIME=1.
428
429 #(CDT) 2016/08/03 17:17:40 - 0 - Hi.
430
431 Example of the output when environment variable NANOSECONDS=1 and
432 SHOW_ELAPSED_TIME=1.
433
434 #(CDT) 2016/08/03 17:18:47.317339 - 0.000046 - Hi.
435
436 Description of arguments.
437 buffer This will be appended to the formatted
438 time string.
439 """
440
441 global NANOSECONDS
442 global SHOW_ELAPSED_TIME
443 global sprint_time_last_seconds
444
445 seconds = time.time()
446 loc_time = time.localtime(seconds)
447 nanoseconds = "%0.6f" % seconds
448 pos = nanoseconds.find(".")
449 nanoseconds = nanoseconds[pos:]
450
451 time_string = time.strftime("#(%Z) %Y/%m/%d %H:%M:%S", loc_time)
452 if NANOSECONDS == "1":
453 time_string = time_string + nanoseconds
454
455 if SHOW_ELAPSED_TIME == "1":
456 cur_time_seconds = seconds
457 math_string = "%9.9f" % cur_time_seconds + " - " + "%9.9f" % \
458 sprint_time_last_seconds
459 elapsed_seconds = eval(math_string)
460 if NANOSECONDS == "1":
461 elapsed_seconds = "%11.6f" % elapsed_seconds
462 else:
463 elapsed_seconds = "%4i" % elapsed_seconds
464 sprint_time_last_seconds = cur_time_seconds
465 time_string = time_string + " - " + elapsed_seconds
466
467 return time_string + " - " + buffer
468
469###############################################################################
470
471
472###############################################################################
473def sprint_timen(buffer=""):
474
475 r"""
476 Append a line feed to the buffer, pass it to sprint_time and return the
477 result.
478 """
479
480 return sprint_time(buffer + "\n")
481
482###############################################################################
483
484
485###############################################################################
486def sprint_error(buffer=""):
487
488 r"""
489 Return a standardized error string. This includes:
490 - A time stamp
491 - The "**ERROR**" string
492 - The caller's buffer string.
493
494 Example:
495
496 The following python code...
497
498 print(sprint_error("Oops.\n"))
499
500 Will result in the following type of output:
501
502 #(CDT) 2016/08/03 17:12:05 - **ERROR** Oops.
503
504 Description of arguments.
505 buffer This will be appended to the formatted
506 error string.
507 """
508
509 return sprint_time() + "**ERROR** " + buffer
510
511###############################################################################
512
513
514###############################################################################
515def sprint_varx(var_name,
516 var_value,
517 hex=0,
518 loc_col1_indent=col1_indent,
Michael Walsh7423c012016-10-04 10:27:21 -0500519 loc_col1_width=col1_width,
520 trailing_char="\n"):
Michael Walshde791732016-09-06 14:25:24 -0500521
522 r"""
523 Print the var name/value passed to it. If the caller lets loc_col1_width
524 default, the printing lines up nicely with output generated by the
525 print_time functions.
526
527 Note that the sprint_var function (defined below) can be used to call this
528 function so that the programmer does not need to pass the var_name.
529 sprint_var will figure out the var_name. The sprint_var function is the
530 one that would normally be used by the general user.
531
532 For example, the following python code:
533
534 first_name = "Mike"
535 print_time("Doing this...\n")
536 print_varx("first_name", first_name)
537 print_time("Doing that...\n")
538
539 Will generate output like this:
540
541 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this...
542 first_name: Mike
543 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that...
544
545 This function recognizes several complex types of data such as dict, list
546 or tuple.
547
548 For example, the following python code:
549
550 my_dict = dict(one=1, two=2, three=3)
551 print_var(my_dict)
552
553 Will generate the following output:
554
555 my_dict:
556 my_dict[three]: 3
557 my_dict[two]: 2
558 my_dict[one]: 1
559
560 Description of arguments.
561 var_name The name of the variable to be printed.
562 var_value The value of the variable to be printed.
563 hex This indicates that the value should be
564 printed in hex format. It is the user's
565 responsibility to ensure that a var_value
Michael Walshbec416d2016-11-10 08:54:52 -0600566 contains a valid hex number. For string
567 var_values, this will be interpreted as
568 show_blanks which means that blank values
Michael Walshd995cb02017-02-07 14:46:01 -0600569 will be printed as "<blank>". For dict
570 var_values, this will be interpreted as
571 terse format where keys are not repeated
572 in the output.
Michael Walshde791732016-09-06 14:25:24 -0500573 loc_col1_indent The number of spaces to indent the output.
574 loc_col1_width The width of the output column containing
575 the variable name. The default value of
576 this is adjusted so that the var_value
577 lines up with text printed via the
578 print_time function.
Michael Walsh7423c012016-10-04 10:27:21 -0500579 trailing_char The character to be used at the end of the
580 returned string. The default value is a
581 line feed.
582 """
Michael Walshde791732016-09-06 14:25:24 -0500583
584 # Determine the type
585 if type(var_value) in (int, float, bool, str, unicode) \
586 or var_value is None:
587 # The data type is simple in the sense that it has no subordinate
588 # parts.
Michael Walsh7423c012016-10-04 10:27:21 -0500589 # Adjust loc_col1_width.
590 loc_col1_width = loc_col1_width - loc_col1_indent
Michael Walshde791732016-09-06 14:25:24 -0500591 # See if the user wants the output in hex format.
592 if hex:
Michael Walsh18176322016-11-15 15:11:21 -0600593 if type(var_value) not in (int, long):
Michael Walshbec416d2016-11-10 08:54:52 -0600594 value_format = "%s"
Michael Walsh2795edc2016-12-13 16:00:33 -0600595 if var_value == "":
Michael Walshbec416d2016-11-10 08:54:52 -0600596 var_value = "<blank>"
597 else:
598 value_format = "0x%08x"
Michael Walshde791732016-09-06 14:25:24 -0500599 else:
600 value_format = "%s"
601 format_string = "%" + str(loc_col1_indent) + "s%-" \
Michael Walsh7423c012016-10-04 10:27:21 -0500602 + str(loc_col1_width) + "s" + value_format + trailing_char
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600603 return format_string % ("", str(var_name) + ":", var_value)
Michael Walshde791732016-09-06 14:25:24 -0500604 else:
605 # The data type is complex in the sense that it has subordinate parts.
606 format_string = "%" + str(loc_col1_indent) + "s%s\n"
607 buffer = format_string % ("", var_name + ":")
608 loc_col1_indent += 2
Michael Walsh7423c012016-10-04 10:27:21 -0500609 try:
610 length = len(var_value)
611 except TypeError:
Michael Walsh23e7f492017-01-10 11:34:47 -0600612 length = 0
Michael Walsh7423c012016-10-04 10:27:21 -0500613 ix = 0
614 loc_trailing_char = "\n"
Michael Walshbec416d2016-11-10 08:54:52 -0600615 type_is_dict = 0
Michael Walsh23e7f492017-01-10 11:34:47 -0600616 if type(var_value) is dict:
617 type_is_dict = 1
Michael Walsh8e6deb42017-01-27 14:22:41 -0600618 try:
619 if type(var_value) is collections.OrderedDict:
620 type_is_dict = 1
621 except AttributeError:
622 pass
623 try:
624 if type(var_value) is DotDict:
625 type_is_dict = 1
626 except NameError:
627 pass
628 try:
629 if type(var_value) is NormalizedDict:
630 type_is_dict = 1
631 except NameError:
632 pass
Michael Walshbec416d2016-11-10 08:54:52 -0600633 if type_is_dict:
Michael Walshde791732016-09-06 14:25:24 -0500634 for key, value in var_value.iteritems():
Michael Walsh7423c012016-10-04 10:27:21 -0500635 ix += 1
636 if ix == length:
637 loc_trailing_char = trailing_char
Michael Walshd995cb02017-02-07 14:46:01 -0600638 if hex:
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600639 # Since hex is being used as a format type, we want it
640 # turned off when processing integer dictionary values so
641 # it is not interpreted as a hex indicator.
642 loc_hex = not (type(value) is int)
Michael Walshd995cb02017-02-07 14:46:01 -0600643 buffer += sprint_varx(key, value,
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600644 loc_hex, loc_col1_indent,
645 loc_col1_width,
Michael Walshd995cb02017-02-07 14:46:01 -0600646 loc_trailing_char)
647 else:
648 buffer += sprint_varx(var_name + "[" + key + "]", value,
649 hex, loc_col1_indent, loc_col1_width,
650 loc_trailing_char)
Michael Walsh7423c012016-10-04 10:27:21 -0500651 elif type(var_value) in (list, tuple, set):
Michael Walshde791732016-09-06 14:25:24 -0500652 for key, value in enumerate(var_value):
Michael Walsh7423c012016-10-04 10:27:21 -0500653 ix += 1
654 if ix == length:
655 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -0500656 buffer += sprint_varx(var_name + "[" + str(key) + "]", value,
Michael Walsh7423c012016-10-04 10:27:21 -0500657 hex, loc_col1_indent, loc_col1_width,
658 loc_trailing_char)
Michael Walshde791732016-09-06 14:25:24 -0500659 elif type(var_value) is argparse.Namespace:
660 for key in var_value.__dict__:
Michael Walsh7423c012016-10-04 10:27:21 -0500661 ix += 1
662 if ix == length:
663 loc_trailing_char = trailing_char
Michael Walshde791732016-09-06 14:25:24 -0500664 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \
Michael Walsh7423c012016-10-04 10:27:21 -0500665 + ", var_value." + key + ", hex, loc_col1_indent," \
666 + " loc_col1_width, loc_trailing_char)"
Michael Walshde791732016-09-06 14:25:24 -0500667 exec(cmd_buf)
668 else:
669 var_type = type(var_value).__name__
670 func_name = sys._getframe().f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -0500671 var_value = "<" + var_type + " type not supported by " + \
672 func_name + "()>"
Michael Walshde791732016-09-06 14:25:24 -0500673 value_format = "%s"
674 loc_col1_indent -= 2
Michael Walsh7423c012016-10-04 10:27:21 -0500675 # Adjust loc_col1_width.
676 loc_col1_width = loc_col1_width - loc_col1_indent
Michael Walshde791732016-09-06 14:25:24 -0500677 format_string = "%" + str(loc_col1_indent) + "s%-" \
Michael Walsh7423c012016-10-04 10:27:21 -0500678 + str(loc_col1_width) + "s" + value_format + trailing_char
Michael Walsh0f2ea5f2017-02-20 15:55:00 -0600679 return format_string % ("", str(var_name) + ":", var_value)
Michael Walsh23e7f492017-01-10 11:34:47 -0600680
Michael Walshde791732016-09-06 14:25:24 -0500681 return buffer
682
683 return ""
684
685###############################################################################
686
687
688###############################################################################
689def sprint_var(*args):
690
691 r"""
692 Figure out the name of the first argument for you and then call
693 sprint_varx with it. Therefore, the following 2 calls are equivalent:
694 sprint_varx("var1", var1)
695 sprint_var(var1)
696 """
697
698 # Get the name of the first variable passed to this function.
699 stack_frame = 2
Michael Walsh7423c012016-10-04 10:27:21 -0500700 caller_func_name = sprint_func_name(2)
701 if caller_func_name.endswith("print_var"):
Michael Walshde791732016-09-06 14:25:24 -0500702 stack_frame += 1
703 var_name = get_arg_name(None, 1, stack_frame)
704 return sprint_varx(var_name, *args)
705
706###############################################################################
707
708
709###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600710def sprint_vars(*args):
711
712 r"""
713 Sprint the values of one or more variables.
714
715 Description of args:
716 args:
717 If the first argument is an integer, it will be interpreted to be the
718 "indent" value.
719 If the second argument is an integer, it will be interpreted to be the
720 "col1_width" value.
721 If the third argument is an integer, it will be interpreted to be the
722 "hex" value.
723 All remaining parms are considered variable names which are to be
724 sprinted.
725 """
726
727 if len(args) == 0:
728 return
729
730 # Get the name of the first variable passed to this function.
731 stack_frame = 2
732 caller_func_name = sprint_func_name(2)
733 if caller_func_name.endswith("print_vars"):
734 stack_frame += 1
735
736 parm_num = 1
737
738 # Create list from args (which is a tuple) so that it can be modified.
739 args_list = list(args)
740
741 var_name = get_arg_name(None, parm_num, stack_frame)
742 # See if parm 1 is to be interpreted as "indent".
743 try:
744 if type(int(var_name)) is int:
745 indent = int(var_name)
746 args_list.pop(0)
747 parm_num += 1
748 except ValueError:
749 indent = 0
750
751 var_name = get_arg_name(None, parm_num, stack_frame)
752 # See if parm 1 is to be interpreted as "col1_width".
753 try:
754 if type(int(var_name)) is int:
755 loc_col1_width = int(var_name)
756 args_list.pop(0)
757 parm_num += 1
758 except ValueError:
759 loc_col1_width = col1_width
760
761 var_name = get_arg_name(None, parm_num, stack_frame)
762 # See if parm 1 is to be interpreted as "hex".
763 try:
764 if type(int(var_name)) is int:
765 hex = int(var_name)
766 args_list.pop(0)
767 parm_num += 1
768 except ValueError:
769 hex = 0
770
771 buffer = ""
772 for var_value in args_list:
773 var_name = get_arg_name(None, parm_num, stack_frame)
774 buffer += sprint_varx(var_name, var_value, hex, indent, loc_col1_width)
775 parm_num += 1
776
777 return buffer
778
779###############################################################################
780
781
782###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500783def lprint_varx(var_name,
784 var_value,
785 hex=0,
786 loc_col1_indent=col1_indent,
787 loc_col1_width=col1_width,
788 log_level=getattr(logging, 'INFO')):
789
790 r"""
791 Send sprint_varx output to logging.
792 """
793
794 logging.log(log_level, sprint_varx(var_name, var_value, hex,
795 loc_col1_indent, loc_col1_width, ""))
796
797###############################################################################
798
799
800###############################################################################
801def lprint_var(*args):
802
803 r"""
804 Figure out the name of the first argument for you and then call
805 lprint_varx with it. Therefore, the following 2 calls are equivalent:
806 lprint_varx("var1", var1)
807 lprint_var(var1)
808 """
809
810 # Get the name of the first variable passed to this function.
811 stack_frame = 2
812 caller_func_name = sprint_func_name(2)
813 if caller_func_name.endswith("print_var"):
814 stack_frame += 1
815 var_name = get_arg_name(None, 1, stack_frame)
816 lprint_varx(var_name, *args)
817
818###############################################################################
819
820
821###############################################################################
822def sprint_dashes(indent=col1_indent,
823 width=80,
824 line_feed=1,
825 char="-"):
Michael Walshde791732016-09-06 14:25:24 -0500826
827 r"""
828 Return a string of dashes to the caller.
829
830 Description of arguements:
831 indent The number of characters to indent the
832 output.
833 width The width of the string of dashes.
834 line_feed Indicates whether the output should end
835 with a line feed.
Michael Walsh7423c012016-10-04 10:27:21 -0500836 char The character to be repeated in the output
837 string.
Michael Walshde791732016-09-06 14:25:24 -0500838 """
839
Michael Walsh7423c012016-10-04 10:27:21 -0500840 width = int(width)
Michael Walsh23e7f492017-01-10 11:34:47 -0600841 buffer = " " * int(indent) + char * width
Michael Walshde791732016-09-06 14:25:24 -0500842 if line_feed:
843 buffer += "\n"
844
845 return buffer
846
847###############################################################################
848
849
850###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500851def sindent(text="",
852 indent=0):
853
854 r"""
855 Pre-pend the specified number of characters to the text string (i.e.
856 indent it) and return it.
857
858 Description of arguments:
859 text The string to be indented.
860 indent The number of characters to indent the
861 string.
862 """
863
864 format_string = "%" + str(indent) + "s%s"
865 buffer = format_string % ("", text)
866
867 return buffer
868
869###############################################################################
870
871
872###############################################################################
873def sprint_call_stack(indent=0,
874 stack_frame_ix=0):
Michael Walshde791732016-09-06 14:25:24 -0500875
876 r"""
877 Return a call stack report for the given point in the program with line
878 numbers, function names and function parameters and arguments.
879
880 Sample output:
881
882 -------------------------------------------------------------------------
883 Python function call stack
884
885 Line # Function name and arguments
886 ------ ------------------------------------------------------------------
887 424 sprint_call_stack ()
888 4 print_call_stack ()
889 31 func1 (last_name = 'walsh', first_name = 'mikey')
890 59 /tmp/scr5.py
891 -------------------------------------------------------------------------
892
893 Description of arguments:
894 indent The number of characters to indent each
895 line of output.
896 stack_frame_ix The index of the first stack frame which
897 is to be returned.
898 """
899
900 buffer = ""
Michael Walsh7423c012016-10-04 10:27:21 -0500901 buffer += sprint_dashes(indent)
902 buffer += sindent("Python function call stack\n\n", indent)
903 buffer += sindent("Line # Function name and arguments\n", indent)
904 buffer += sprint_dashes(indent, 6, 0) + " " + sprint_dashes(0, 73)
Michael Walshde791732016-09-06 14:25:24 -0500905
906 # Grab the current program stack.
907 current_stack = inspect.stack()
908
909 # Process each frame in turn.
910 format_string = "%6s %s\n"
Michael Walsh7423c012016-10-04 10:27:21 -0500911 ix = 0
Michael Walshde791732016-09-06 14:25:24 -0500912 for stack_frame in current_stack:
Michael Walsh7423c012016-10-04 10:27:21 -0500913 if ix < stack_frame_ix:
914 ix += 1
915 continue
Michael Walsh23e7f492017-01-10 11:34:47 -0600916 # I want the line number shown to be the line where you find the line
917 # shown.
918 try:
919 line_num = str(current_stack[ix + 1][2])
920 except IndexError:
921 line_num = ""
Michael Walshde791732016-09-06 14:25:24 -0500922 func_name = str(stack_frame[3])
923 if func_name == "?":
924 # "?" is the name used when code is not in a function.
925 func_name = "(none)"
926
927 if func_name == "<module>":
Michael Walsh7423c012016-10-04 10:27:21 -0500928 # If the func_name is the "main" program, we simply get the
929 # command line call string.
Michael Walshde791732016-09-06 14:25:24 -0500930 func_and_args = ' '.join(sys.argv)
931 else:
932 # Get the program arguments.
933 arg_vals = inspect.getargvalues(stack_frame[0])
934 function_parms = arg_vals[0]
935 frame_locals = arg_vals[3]
936
Michael Walsh7423c012016-10-04 10:27:21 -0500937 args_list = []
Michael Walshde791732016-09-06 14:25:24 -0500938 for arg_name in function_parms:
939 # Get the arg value from frame locals.
940 arg_value = frame_locals[arg_name]
Michael Walsh7423c012016-10-04 10:27:21 -0500941 args_list.append(arg_name + " = " + repr(arg_value))
942 args_str = "(" + ', '.join(map(str, args_list)) + ")"
Michael Walshde791732016-09-06 14:25:24 -0500943
944 # Now we need to print this in a nicely-wrapped way.
945 func_and_args = func_name + " " + args_str
946
Michael Walsh23e7f492017-01-10 11:34:47 -0600947 buffer += sindent(format_string % (line_num, func_and_args), indent)
Michael Walsh7423c012016-10-04 10:27:21 -0500948 ix += 1
Michael Walshde791732016-09-06 14:25:24 -0500949
Michael Walsh7423c012016-10-04 10:27:21 -0500950 buffer += sprint_dashes(indent)
Michael Walshde791732016-09-06 14:25:24 -0500951
952 return buffer
953
954###############################################################################
955
956
957###############################################################################
958def sprint_executing(stack_frame_ix=None):
959
960 r"""
961 Print a line indicating what function is executing and with what parameter
962 values. This is useful for debugging.
963
964 Sample output:
965
966 #(CDT) 2016/08/25 17:54:27 - Executing: func1 (x = 1)
967
968 Description of arguments:
969 stack_frame_ix The index of the stack frame whose
970 function info should be returned. If the
971 caller does not specifiy a value, this
972 function will set the value to 1 which is
973 the index of the caller's stack frame. If
974 the caller is the wrapper function
975 "print_executing", this function will bump
976 it up by 1.
977 """
978
979 # If user wants default stack_frame_ix.
980 if stack_frame_ix is None:
981 func_name = sys._getframe().f_code.co_name
982 caller_func_name = sys._getframe(1).f_code.co_name
Michael Walsh7423c012016-10-04 10:27:21 -0500983 if caller_func_name.endswith(func_name[1:]):
Michael Walshde791732016-09-06 14:25:24 -0500984 stack_frame_ix = 2
985 else:
986 stack_frame_ix = 1
987
988 stack_frame = inspect.stack()[stack_frame_ix]
989
990 func_name = str(stack_frame[3])
991 if func_name == "?":
992 # "?" is the name used when code is not in a function.
993 func_name = "(none)"
994
995 if func_name == "<module>":
996 # If the func_name is the "main" program, we simply get the command
997 # line call string.
998 func_and_args = ' '.join(sys.argv)
999 else:
1000 # Get the program arguments.
1001 arg_vals = inspect.getargvalues(stack_frame[0])
1002 function_parms = arg_vals[0]
1003 frame_locals = arg_vals[3]
1004
Michael Walsh7423c012016-10-04 10:27:21 -05001005 args_list = []
Michael Walshde791732016-09-06 14:25:24 -05001006 for arg_name in function_parms:
1007 # Get the arg value from frame locals.
1008 arg_value = frame_locals[arg_name]
Michael Walsh7423c012016-10-04 10:27:21 -05001009 args_list.append(arg_name + " = " + repr(arg_value))
1010 args_str = "(" + ', '.join(map(str, args_list)) + ")"
Michael Walshde791732016-09-06 14:25:24 -05001011
1012 # Now we need to print this in a nicely-wrapped way.
1013 func_and_args = func_name + " " + args_str
1014
1015 return sprint_time() + "Executing: " + func_and_args + "\n"
1016
1017###############################################################################
1018
1019
1020###############################################################################
Michael Walshbec416d2016-11-10 08:54:52 -06001021def sprint_pgm_header(indent=0,
1022 linefeed=1):
Michael Walshde791732016-09-06 14:25:24 -05001023
1024 r"""
1025 Return a standardized header that programs should print at the beginning
1026 of the run. It includes useful information like command line, pid,
1027 userid, program parameters, etc.
1028
Michael Walsh7423c012016-10-04 10:27:21 -05001029 Description of arguments:
1030 indent The number of characters to indent each
1031 line of output.
Michael Walshbec416d2016-11-10 08:54:52 -06001032 linefeed Indicates whether a line feed be included
1033 at the beginning and end of the report.
Michael Walshde791732016-09-06 14:25:24 -05001034 """
1035
Michael Walshbec416d2016-11-10 08:54:52 -06001036 loc_col1_width = col1_width + indent
1037
1038 buffer = ""
1039 if linefeed:
1040 buffer = "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001041
1042 buffer += sindent(sprint_time() + "Running " + pgm_name + ".\n", indent)
1043 buffer += sindent(sprint_time() + "Program parameter values, etc.:\n\n",
1044 indent)
Michael Walshbec416d2016-11-10 08:54:52 -06001045 buffer += sprint_varx("command_line", ' '.join(sys.argv), 0, indent,
1046 loc_col1_width)
Michael Walsh7423c012016-10-04 10:27:21 -05001047 # We want the output to show a customized name for the pid and pgid but
1048 # we want it to look like a valid variable name. Therefore, we'll use
Michael Walshde791732016-09-06 14:25:24 -05001049 # pgm_name_var_name which was set when this module was imported.
Michael Walshbec416d2016-11-10 08:54:52 -06001050 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid(), 0, indent,
1051 loc_col1_width)
1052 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp(), 0, indent,
1053 loc_col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001054 userid_num = str(os.geteuid())
1055 try:
1056 username = os.getlogin()
1057 except OSError:
1058 if userid_num == "0":
1059 username = "root"
1060 else:
1061 username = "?"
1062 buffer += sprint_varx("uid", userid_num + " (" + username +
Michael Walshbec416d2016-11-10 08:54:52 -06001063 ")", 0, indent, loc_col1_width)
Michael Walshde791732016-09-06 14:25:24 -05001064 buffer += sprint_varx("gid", str(os.getgid()) + " (" +
Michael Walsh7423c012016-10-04 10:27:21 -05001065 str(grp.getgrgid(os.getgid()).gr_name) + ")", 0,
Michael Walshbec416d2016-11-10 08:54:52 -06001066 indent, loc_col1_width)
1067 buffer += sprint_varx("host_name", socket.gethostname(), 0, indent,
1068 loc_col1_width)
Michael Walsh86de0d22016-12-05 10:13:15 -06001069 try:
1070 DISPLAY = os.environ['DISPLAY']
1071 except KeyError:
1072 DISPLAY = ""
1073 buffer += sprint_varx("DISPLAY", DISPLAY, 0, indent,
Michael Walshbec416d2016-11-10 08:54:52 -06001074 loc_col1_width)
Michael Walshde791732016-09-06 14:25:24 -05001075 # I want to add code to print caller's parms.
1076
Michael Walsh7423c012016-10-04 10:27:21 -05001077 # __builtin__.arg_obj is created by the get_arg module function,
1078 # gen_get_options.
1079 try:
1080 buffer += ga.sprint_args(__builtin__.arg_obj, indent)
1081 except AttributeError:
1082 pass
1083
Michael Walshbec416d2016-11-10 08:54:52 -06001084 if linefeed:
1085 buffer += "\n"
Michael Walshde791732016-09-06 14:25:24 -05001086
1087 return buffer
1088
1089###############################################################################
1090
1091
1092###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -05001093def sprint_error_report(error_text="\n",
1094 indent=2):
1095
1096 r"""
1097 Return a string with a standardized report which includes the caller's
1098 error text, the call stack and the program header.
1099
1100 Description of args:
1101 error_text The error text to be included in the
1102 report. The caller should include any
1103 needed linefeeds.
1104 indent The number of characters to indent each
1105 line of output.
1106 """
1107
1108 buffer = ""
1109 buffer += sprint_dashes(width=120, char="=")
1110 buffer += sprint_error(error_text)
1111 buffer += "\n"
1112 # Calling sprint_call_stack with stack_frame_ix of 0 causes it to show
1113 # itself and this function in the call stack. This is not helpful to a
1114 # debugger and is therefore clutter. We will adjust the stack_frame_ix to
1115 # hide that information.
1116 stack_frame_ix = 2
1117 caller_func_name = sprint_func_name(2)
1118 if caller_func_name.endswith("print_error_report"):
1119 stack_frame_ix += 1
1120 buffer += sprint_call_stack(indent, stack_frame_ix)
1121 buffer += sprint_pgm_header(indent)
1122 buffer += sprint_dashes(width=120, char="=")
1123
1124 return buffer
1125
1126###############################################################################
1127
1128
1129###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -06001130def sprint_issuing(cmd_buf,
1131 test_mode=0):
Michael Walshde791732016-09-06 14:25:24 -05001132
1133 r"""
1134 Return a line indicating a command that the program is about to execute.
1135
1136 Sample output for a cmd_buf of "ls"
1137
1138 #(CDT) 2016/08/25 17:57:36 - Issuing: ls
Michael Walshbec416d2016-11-10 08:54:52 -06001139
Michael Walshde791732016-09-06 14:25:24 -05001140 Description of args:
1141 cmd_buf The command to be executed by caller.
Michael Walshbec416d2016-11-10 08:54:52 -06001142 test_mode With test_mode set, your output will look
1143 like this:
1144
1145 #(CDT) 2016/08/25 17:57:36 - (test_mode) Issuing: ls
1146
Michael Walshde791732016-09-06 14:25:24 -05001147 """
1148
Michael Walshbec416d2016-11-10 08:54:52 -06001149 buffer = sprint_time()
1150 if test_mode:
1151 buffer += "(test_mode) "
1152 buffer += "Issuing: " + cmd_buf + "\n"
Michael Walshde791732016-09-06 14:25:24 -05001153
1154 return buffer
1155
1156###############################################################################
1157
1158
1159###############################################################################
1160def sprint_pgm_footer():
1161
1162 r"""
1163 Return a standardized footer that programs should print at the end of the
1164 program run. It includes useful information like total run time, etc.
1165 """
1166
1167 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n"
1168
1169 total_time = time.time() - start_time
1170 total_time_string = "%0.6f" % total_time
1171
Michael Walsh7423c012016-10-04 10:27:21 -05001172 buffer += sprint_varx(pgm_name_var_name + "_runtime", total_time_string)
Michael Walshbec416d2016-11-10 08:54:52 -06001173 buffer += "\n"
Michael Walsh7423c012016-10-04 10:27:21 -05001174
1175 return buffer
1176
1177###############################################################################
1178
1179
1180###############################################################################
1181def sprint(buffer=""):
1182
1183 r"""
1184 Simply return the user's buffer. This function is used by the qprint and
1185 dprint functions defined dynamically below, i.e. it would not normally be
1186 called for general use.
1187
1188 Description of arguments.
1189 buffer This will be returned to the caller.
1190 """
Michael Walshde791732016-09-06 14:25:24 -05001191
Michael Walshbec416d2016-11-10 08:54:52 -06001192 return str(buffer)
1193
1194###############################################################################
1195
1196
1197###############################################################################
1198def sprintn(buffer=""):
1199
1200 r"""
1201 Simply return the user's buffer with a line feed. This function is used
1202 by the qprint and dprint functions defined dynamically below, i.e. it
1203 would not normally be called for general use.
1204
1205 Description of arguments.
1206 buffer This will be returned to the caller.
1207 """
1208
1209 buffer = str(buffer) + "\n"
1210
Michael Walshde791732016-09-06 14:25:24 -05001211 return buffer
1212
1213###############################################################################
1214
1215
1216###############################################################################
1217# In the following section of code, we will dynamically create print versions
1218# for each of the sprint functions defined above. So, for example, where we
1219# have an sprint_time() function defined above that returns the time to the
Michael Walsh7423c012016-10-04 10:27:21 -05001220# caller in a string, we will create a corresponding print_time() function
1221# that will print that string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -05001222
1223# It can be complicated to follow what's being creaed by the exec statement
1224# below. Here is an example of the print_time() function that will be created:
1225
1226# def print_time(*args):
1227# s_funcname = "s" + sys._getframe().f_code.co_name
1228# s_func = getattr(sys.modules[__name__], s_funcname)
1229# sys.stdout.write(s_func(*args))
1230
1231# Here are comments describing the 3 lines in the body of the created function.
1232# Calculate the "s" version of this function name (e.g. if this function name
1233# is print_time, we want s_funcname to be "sprint_time".
1234# Put a reference to the "s" version of this function in s_func.
Michael Walsh7423c012016-10-04 10:27:21 -05001235# Call the "s" version of this function passing it all of our arguments.
1236# Write the result to stdout.
Michael Walshde791732016-09-06 14:25:24 -05001237
1238# func_names contains a list of all print functions which should be created
1239# from their sprint counterparts.
1240func_names = ['print_time', 'print_timen', 'print_error', 'print_varx',
Michael Walsh18176322016-11-15 15:11:21 -06001241 'print_var', 'print_vars', 'print_dashes', 'indent',
1242 'print_call_stack', 'print_func_name', 'print_executing',
1243 'print_pgm_header', 'print_issuing', 'print_pgm_footer',
1244 'print_error_report', 'print', 'printn']
Michael Walshde791732016-09-06 14:25:24 -05001245
1246for func_name in func_names:
Michael Walsh7423c012016-10-04 10:27:21 -05001247 if func_name == "print":
1248 continue
Michael Walshde791732016-09-06 14:25:24 -05001249 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var).
1250 alias = re.sub("print_", "p", func_name)
Michael Walsh7423c012016-10-04 10:27:21 -05001251 pgm_definition_string = "s" + alias + " = s" + func_name
1252 if gen_print_debug:
1253 print(pgm_definition_string)
1254 exec(pgm_definition_string)
Michael Walshde791732016-09-06 14:25:24 -05001255
1256for func_name in func_names:
Michael Walsh7423c012016-10-04 10:27:21 -05001257 if func_name == "print_error" or func_name == "print_error_report":
Michael Walshde791732016-09-06 14:25:24 -05001258 output_stream = "stderr"
1259 else:
1260 output_stream = "stdout"
1261 func_def = \
1262 [
1263 "def " + func_name + "(*args):",
1264 " s_func_name = \"s\" + sys._getframe().f_code.co_name",
1265 " s_func = getattr(sys.modules[__name__], s_func_name)",
1266 " sys." + output_stream + ".write(s_func(*args))",
1267 " sys." + output_stream + ".flush()"
1268 ]
Michael Walsh7423c012016-10-04 10:27:21 -05001269 if func_name != "print":
1270 pgm_definition_string = '\n'.join(func_def)
1271 if gen_print_debug:
1272 print(pgm_definition_string)
1273 exec(pgm_definition_string)
1274
1275 # Now define "q" versions of each print function.
1276 func_def = \
1277 [
1278 "def q" + func_name + "(*args):",
1279 " if __builtin__.quiet: return",
1280 " s_func_name = \"s" + func_name + "\"",
1281 " s_func = getattr(sys.modules[__name__], s_func_name)",
1282 " sys." + output_stream + ".write(s_func(*args))",
1283 " sys." + output_stream + ".flush()"
1284 ]
1285
Michael Walshde791732016-09-06 14:25:24 -05001286 pgm_definition_string = '\n'.join(func_def)
Michael Walsh7423c012016-10-04 10:27:21 -05001287 if gen_print_debug:
1288 print(pgm_definition_string)
Michael Walshde791732016-09-06 14:25:24 -05001289 exec(pgm_definition_string)
1290
Michael Walsh7423c012016-10-04 10:27:21 -05001291 # Now define "d" versions of each print function.
1292 func_def = \
1293 [
1294 "def d" + func_name + "(*args):",
1295 " if not __builtin__.debug: return",
1296 " s_func_name = \"s" + func_name + "\"",
1297 " s_func = getattr(sys.modules[__name__], s_func_name)",
1298 " sys." + output_stream + ".write(s_func(*args))",
1299 " sys." + output_stream + ".flush()"
1300 ]
1301
1302 pgm_definition_string = '\n'.join(func_def)
1303 if gen_print_debug:
1304 print(pgm_definition_string)
1305 exec(pgm_definition_string)
1306
1307 # Now define "l" versions of each print function.
1308 func_def = \
1309 [
1310 "def l" + func_name + "(*args):",
1311 " s_func_name = \"s" + func_name + "\"",
1312 " s_func = getattr(sys.modules[__name__], s_func_name)",
1313 " logging.log(getattr(logging, 'INFO'), s_func(*args))",
1314 ]
1315
1316 if func_name != "print_varx" and func_name != "print_var":
1317 pgm_definition_string = '\n'.join(func_def)
1318 if gen_print_debug:
1319 print(pgm_definition_string)
1320 exec(pgm_definition_string)
1321
1322 if func_name == "print":
1323 continue
1324
Michael Walshde791732016-09-06 14:25:24 -05001325 # Create abbreviated aliases (e.g. pvar is an alias for print_var).
1326 alias = re.sub("print_", "p", func_name)
Michael Walsh7423c012016-10-04 10:27:21 -05001327 pgm_definition_string = alias + " = " + func_name
1328 if gen_print_debug:
1329 print(pgm_definition_string)
1330 exec(pgm_definition_string)
1331
1332 # Create abbreviated aliases (e.g. qpvar is an alias for qprint_var).
1333 alias = re.sub("print_", "p", func_name)
1334 pgm_definition_string = "q" + alias + " = q" + func_name
1335 if gen_print_debug:
1336 print(pgm_definition_string)
1337 exec(pgm_definition_string)
1338
1339 # Create abbreviated aliases (e.g. dpvar is an alias for dprint_var).
1340 alias = re.sub("print_", "p", func_name)
1341 pgm_definition_string = "d" + alias + " = d" + func_name
1342 if gen_print_debug:
1343 print(pgm_definition_string)
1344 exec(pgm_definition_string)
1345
1346 # Create abbreviated aliases (e.g. lpvar is an alias for lprint_var).
1347 alias = re.sub("print_", "p", func_name)
1348 pgm_definition_string = "l" + alias + " = l" + func_name
1349 if gen_print_debug:
1350 print(pgm_definition_string)
1351 exec(pgm_definition_string)
Michael Walshde791732016-09-06 14:25:24 -05001352
1353###############################################################################