blob: c4618cc552fcef66d6031a8d12a941628a228b8b [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
16
17# Setting these variables for use both inside this module and by programs
18# importing this module.
19pgm_dir_path = sys.argv[0]
20pgm_name = os.path.basename(pgm_dir_path)
21
22# Some functions (e.g. sprint_pgm_header) have need of a program name value
23# that looks more like a valid variable name. Therefore, we'll swap odd
24# characters like "." out for underscores.
25pgm_name_var_name = pgm_name.replace(".", "_")
26
27# Initialize global values used as defaults by print_time, print_var, etc.
28col1_indent = 0
29
30# Calculate default column width for print_var functions based on environment
31# variable settings. The objective is to make the variable values line up
32# nicely with the time stamps.
33col1_width = 29
34if 'NANOSECONDS' in os.environ:
35 NANOSECONDS = os.environ['NANOSECONDS']
36else:
37 NANOSECONDS = 0
38
39if NANOSECONDS == "1":
40 col1_width = col1_width + 7
41
42if 'SHOW_ELAPSED_TIME' in os.environ:
43 SHOW_ELAPSED_TIME = os.environ['SHOW_ELAPSED_TIME']
44else:
45 SHOW_ELAPSED_TIME = 0
46
47if SHOW_ELAPSED_TIME == "1":
48 if NANOSECONDS == "1":
49 col1_width = col1_width + 14
50 else:
51 col1_width = col1_width + 7
52
53# Initialize some time variables used in module functions.
54start_time = time.time()
55sprint_time_last_seconds = start_time
56
57
58###############################################################################
59def sprint_func_name(stack_frame_ix=None):
60
61 r"""
62 Return the function name associated with the indicated stack frame.
63
64 Description of arguments:
65 stack_frame_ix The index of the stack frame whose
66 function name should be returned. If the
67 caller does not specifiy a value, this
68 function will set the value to 1 which is
69 the index of the caller's stack frame. If
70 the caller is the wrapper function
71 "print_func_name", this function will bump
72 it up by 1.
73 """
74
75 # If user specified no stack_frame_ix, we'll set it to a proper default
76 # value.
77 if stack_frame_ix is None:
78 func_name = sys._getframe().f_code.co_name
79 caller_func_name = sys._getframe(1).f_code.co_name
80 if func_name[1:] == caller_func_name:
81 stack_frame_ix = 2
82 else:
83 stack_frame_ix = 1
84
85 func_name = sys._getframe(stack_frame_ix).f_code.co_name
86
87 return func_name
88
89###############################################################################
90
91
92# get_arg_name is not a print function per se. I have included it in this
93# module because it is used by sprint_var which is found in this module.
94###############################################################################
95def get_arg_name(var,
96 arg_num=1,
97 stack_frame_ix=1):
98
99 r"""
100 Return the "name" of an argument passed to a function. This could be a
101 literal or a variable name.
102
103 Description of arguements:
104 var The variable whose name you want returned.
105 arg_num The arg number (1 through n) whose name
106 you wish to have returned. This value
107 should not exceed the number of arguments
108 allowed by the target function.
109 stack_frame_ix The stack frame index of the target
110 function. This value must be 1 or
111 greater. 1 would indicate get_arg_name's
112 stack frame. 2 would be the caller of
113 get_arg_name's stack frame, etc.
114
115 Example 1:
116
117 my_var = "mike"
118 var_name = get_arg_name(my_var)
119
120 In this example, var_name will receive the value "my_var".
121
122 Example 2:
123
124 def test1(var):
125 # Getting the var name of the first arg to this function, test1.
126 # Note, in this case, it doesn't matter what you pass as the first arg
127 # to get_arg_name since it is the caller's variable name that matters.
128 dummy = 1
129 arg_num = 1
130 stack_frame = 2
131 var_name = get_arg_name(dummy, arg_num, stack_frame)
132
133 # Mainline...
134
135 another_var = "whatever"
136 test1(another_var)
137
138 In this example, var_name will be set to "another_var".
139
140 """
141
142 # Note: I wish to avoid recursion so I refrain from calling any function
143 # that calls this function (i.e. sprint_var, valid_value, etc.).
144
145 try:
146 # The user can set environment variable "GET_ARG_NAME_DEBUG" to get
147 # debug output from this function.
148 local_debug = os.environ['GET_ARG_NAME_DEBUG']
149 except KeyError:
150 local_debug = 0
151
152 if arg_num < 1:
153 print_error("Programmer error - Variable \"arg_num\" has an invalid" +
154 " value of \"" + str(arg_num) + "\". The value must be" +
155 " an integer that is greater than 0.\n")
156 # What is the best way to handle errors? Raise exception? I'll
157 # revisit later.
158 return
159 if stack_frame_ix < 1:
160 print_error("Programmer error - Variable \"stack_frame_ix\" has an" +
161 " invalid value of \"" + str(stack_frame_ix) + "\". The" +
162 " value must be an integer that is greater than or equal" +
163 " to 1.\n")
164 return
165
166 if local_debug:
167 debug_indent = 2
168 print(sprint_func_name() + "() parms:")
169 print_varx("var", var, 0, debug_indent)
170 print_varx("arg_num", arg_num, 0, debug_indent)
171 print_varx("stack_frame_ix", stack_frame_ix, 0, debug_indent)
172
173 try:
174 frame, filename, cur_line_no, function_name, lines, index = \
175 inspect.stack()[stack_frame_ix]
176 except IndexError:
177 print_error("Programmer error - The caller has asked for information" +
178 " about the stack frame at index \"" +
179 str(stack_frame_ix) + "\". However, the stack only" +
180 " contains " + str(len(inspect.stack())) + " entries." +
181 " Therefore the stack frame index is out of range.\n")
182 return
183
184 if local_debug:
185 print("\nVariables retrieved from inspect.stack() function:")
186 print_varx("frame", frame, 0, debug_indent)
187 print_varx("filename", filename, 0, debug_indent)
188 print_varx("cur_line_no", cur_line_no, 0, debug_indent)
189 print_varx("function_name", function_name, 0, debug_indent)
190 print_varx("lines", lines, 0, debug_indent)
191 print_varx("index", index, 0, debug_indent)
192
193 composite_line = lines[0].strip()
194
195 called_func_name = sprint_func_name(stack_frame_ix)
196 # 2016/09/01 Mike Walsh (xzy0065) - I added code to handle pvar alias.
197 # pvar is an alias for print_var. However, when it is used,
198 # sprint_func_name() returns the non-alias version, i.e. "print_var".
199 # Adjusting for that here.
200 substring = composite_line[0:4]
201 if substring == "pvar":
202 called_func_name = "pvar"
203 arg_list_etc = re.sub(".*" + called_func_name, "", composite_line)
204 if local_debug:
205 print_varx("called_func_name", called_func_name, 0, debug_indent)
206 print_varx("composite_line", composite_line, 0, debug_indent)
207 print_varx("arg_list_etc", arg_list_etc, 0, debug_indent)
208
209 # Parse arg list...
210 # Initialize...
211 nest_level = -1
212 arg_ix = 0
213 args_arr = [""]
214 for ix in range(0, len(arg_list_etc)):
215 char = arg_list_etc[ix]
216 # Set the nest_level based on whether we've encounted a parenthesis.
217 if char == "(":
218 nest_level += 1
219 if nest_level == 0:
220 continue
221 elif char == ")":
222 nest_level -= 1
223 if nest_level < 0:
224 break
225
226 # If we reach a comma at base nest level, we are done processing an
227 # argument so we increment arg_ix and initialize a new args_arr entry.
228 if char == "," and nest_level == 0:
229 arg_ix += 1
230 args_arr.append("")
231 continue
232
233 # For any other character, we append it it to the current arg array
234 # entry.
235 args_arr[arg_ix] += char
236
237 # Trim whitespace from each list entry.
238 args_arr = [arg.strip() for arg in args_arr]
239
240 if arg_num > len(args_arr):
241 print_error("Programmer error - The caller has asked for the name of" +
242 " argument number \"" + str(arg_num) + "\" but there " +
243 "were only \"" + str(len(args_arr)) + "\" args used:\n" +
244 sprint_varx("args_arr", args_arr))
245 return
246
247 argument = args_arr[arg_num - 1]
248
249 if local_debug:
250 print_varx("args_arr", args_arr, 0, debug_indent)
251 print_varx("argument", argument, 0, debug_indent)
252
253 return argument
254
255###############################################################################
256
257
258###############################################################################
259def sprint_time(buffer=""):
260
261 r"""
262 Return the time in the following format.
263
264 Example:
265
266 The following python code...
267
268 sys.stdout.write(sprint_time())
269 sys.stdout.write("Hi.\n")
270
271 Will result in the following type of output:
272
273 #(CDT) 2016/07/08 15:25:35 - Hi.
274
275 Example:
276
277 The following python code...
278
279 sys.stdout.write(sprint_time("Hi.\n"))
280
281 Will result in the following type of output:
282
283 #(CDT) 2016/08/03 17:12:05 - Hi.
284
285 The following environment variables will affect the formatting as
286 described:
287 NANOSECONDS This will cause the time stamps to be
288 precise to the microsecond (Yes, it
289 probably should have been named
290 MICROSECONDS but the convention was set
291 long ago so we're sticking with it).
292 Example of the output when environment
293 variable NANOSECONDS=1.
294
295 #(CDT) 2016/08/03 17:16:25.510469 - Hi.
296
297 SHOW_ELAPSED_TIME This will cause the elapsed time to be
298 included in the output. This is the
299 amount of time that has elapsed since the
300 last time this function was called. The
301 precision of the elapsed time field is
302 also affected by the value of the
303 NANOSECONDS environment variable. Example
304 of the output when environment variable
305 NANOSECONDS=0 and SHOW_ELAPSED_TIME=1.
306
307 #(CDT) 2016/08/03 17:17:40 - 0 - Hi.
308
309 Example of the output when environment variable NANOSECONDS=1 and
310 SHOW_ELAPSED_TIME=1.
311
312 #(CDT) 2016/08/03 17:18:47.317339 - 0.000046 - Hi.
313
314 Description of arguments.
315 buffer This will be appended to the formatted
316 time string.
317 """
318
319 global NANOSECONDS
320 global SHOW_ELAPSED_TIME
321 global sprint_time_last_seconds
322
323 seconds = time.time()
324 loc_time = time.localtime(seconds)
325 nanoseconds = "%0.6f" % seconds
326 pos = nanoseconds.find(".")
327 nanoseconds = nanoseconds[pos:]
328
329 time_string = time.strftime("#(%Z) %Y/%m/%d %H:%M:%S", loc_time)
330 if NANOSECONDS == "1":
331 time_string = time_string + nanoseconds
332
333 if SHOW_ELAPSED_TIME == "1":
334 cur_time_seconds = seconds
335 math_string = "%9.9f" % cur_time_seconds + " - " + "%9.9f" % \
336 sprint_time_last_seconds
337 elapsed_seconds = eval(math_string)
338 if NANOSECONDS == "1":
339 elapsed_seconds = "%11.6f" % elapsed_seconds
340 else:
341 elapsed_seconds = "%4i" % elapsed_seconds
342 sprint_time_last_seconds = cur_time_seconds
343 time_string = time_string + " - " + elapsed_seconds
344
345 return time_string + " - " + buffer
346
347###############################################################################
348
349
350###############################################################################
351def sprint_timen(buffer=""):
352
353 r"""
354 Append a line feed to the buffer, pass it to sprint_time and return the
355 result.
356 """
357
358 return sprint_time(buffer + "\n")
359
360###############################################################################
361
362
363###############################################################################
364def sprint_error(buffer=""):
365
366 r"""
367 Return a standardized error string. This includes:
368 - A time stamp
369 - The "**ERROR**" string
370 - The caller's buffer string.
371
372 Example:
373
374 The following python code...
375
376 print(sprint_error("Oops.\n"))
377
378 Will result in the following type of output:
379
380 #(CDT) 2016/08/03 17:12:05 - **ERROR** Oops.
381
382 Description of arguments.
383 buffer This will be appended to the formatted
384 error string.
385 """
386
387 return sprint_time() + "**ERROR** " + buffer
388
389###############################################################################
390
391
392###############################################################################
393def sprint_varx(var_name,
394 var_value,
395 hex=0,
396 loc_col1_indent=col1_indent,
397 loc_col1_width=col1_width):
398
399 r"""
400 Print the var name/value passed to it. If the caller lets loc_col1_width
401 default, the printing lines up nicely with output generated by the
402 print_time functions.
403
404 Note that the sprint_var function (defined below) can be used to call this
405 function so that the programmer does not need to pass the var_name.
406 sprint_var will figure out the var_name. The sprint_var function is the
407 one that would normally be used by the general user.
408
409 For example, the following python code:
410
411 first_name = "Mike"
412 print_time("Doing this...\n")
413 print_varx("first_name", first_name)
414 print_time("Doing that...\n")
415
416 Will generate output like this:
417
418 #(CDT) 2016/08/10 17:34:42.847374 - 0.001285 - Doing this...
419 first_name: Mike
420 #(CDT) 2016/08/10 17:34:42.847510 - 0.000136 - Doing that...
421
422 This function recognizes several complex types of data such as dict, list
423 or tuple.
424
425 For example, the following python code:
426
427 my_dict = dict(one=1, two=2, three=3)
428 print_var(my_dict)
429
430 Will generate the following output:
431
432 my_dict:
433 my_dict[three]: 3
434 my_dict[two]: 2
435 my_dict[one]: 1
436
437 Description of arguments.
438 var_name The name of the variable to be printed.
439 var_value The value of the variable to be printed.
440 hex This indicates that the value should be
441 printed in hex format. It is the user's
442 responsibility to ensure that a var_value
443 contains a valid hex number.
444 loc_col1_indent The number of spaces to indent the output.
445 loc_col1_width The width of the output column containing
446 the variable name. The default value of
447 this is adjusted so that the var_value
448 lines up with text printed via the
449 print_time function.
450 """
451
452 # Adjust loc_col1_width.
453 loc_col1_width = loc_col1_width - loc_col1_indent
454
455 # Determine the type
456 if type(var_value) in (int, float, bool, str, unicode) \
457 or var_value is None:
458 # The data type is simple in the sense that it has no subordinate
459 # parts.
460 # See if the user wants the output in hex format.
461 if hex:
462 value_format = "0x%08x"
463 else:
464 value_format = "%s"
465 format_string = "%" + str(loc_col1_indent) + "s%-" \
466 + str(loc_col1_width) + "s" + value_format + "\n"
467 return format_string % ("", var_name + ":", var_value)
468 else:
469 # The data type is complex in the sense that it has subordinate parts.
470 format_string = "%" + str(loc_col1_indent) + "s%s\n"
471 buffer = format_string % ("", var_name + ":")
472 loc_col1_indent += 2
473 if type(var_value) is dict:
474 for key, value in var_value.iteritems():
475 buffer += sprint_varx(var_name + "[" + key + "]", value, hex,
476 loc_col1_indent)
477 elif type(var_value) in (list, tuple):
478 for key, value in enumerate(var_value):
479 buffer += sprint_varx(var_name + "[" + str(key) + "]", value,
480 hex, loc_col1_indent)
481 elif type(var_value) is argparse.Namespace:
482 for key in var_value.__dict__:
483 cmd_buf = "buffer += sprint_varx(var_name + \".\" + str(key)" \
484 + ", var_value." + key + ", hex, loc_col1_indent)"
485 exec(cmd_buf)
486 else:
487 var_type = type(var_value).__name__
488 func_name = sys._getframe().f_code.co_name
489 var_value = "<" + var_type + " type not supported by " \
490 + func_name + "()>"
491 value_format = "%s"
492 loc_col1_indent -= 2
493 format_string = "%" + str(loc_col1_indent) + "s%-" \
494 + str(loc_col1_width) + "s" + value_format + "\n"
495 return format_string % ("", var_name + ":", var_value)
496 return buffer
497
498 return ""
499
500###############################################################################
501
502
503###############################################################################
504def sprint_var(*args):
505
506 r"""
507 Figure out the name of the first argument for you and then call
508 sprint_varx with it. Therefore, the following 2 calls are equivalent:
509 sprint_varx("var1", var1)
510 sprint_var(var1)
511 """
512
513 # Get the name of the first variable passed to this function.
514 stack_frame = 2
515 calling_func_name = sprint_func_name(2)
516 if calling_func_name == "print_var":
517 stack_frame += 1
518 var_name = get_arg_name(None, 1, stack_frame)
519 return sprint_varx(var_name, *args)
520
521###############################################################################
522
523
524###############################################################################
525def sprint_dashes(loc_col1_indent=col1_indent,
526 col_width=80,
527 line_feed=1):
528
529 r"""
530 Return a string of dashes to the caller.
531
532 Description of arguements:
533 indent The number of characters to indent the
534 output.
535 width The width of the string of dashes.
536 line_feed Indicates whether the output should end
537 with a line feed.
538 """
539
540 col_width = int(col_width)
541 buffer = " "*int(loc_col1_indent) + "-"*col_width
542 if line_feed:
543 buffer += "\n"
544
545 return buffer
546
547###############################################################################
548
549
550###############################################################################
551def sprint_call_stack():
552
553 r"""
554 Return a call stack report for the given point in the program with line
555 numbers, function names and function parameters and arguments.
556
557 Sample output:
558
559 -------------------------------------------------------------------------
560 Python function call stack
561
562 Line # Function name and arguments
563 ------ ------------------------------------------------------------------
564 424 sprint_call_stack ()
565 4 print_call_stack ()
566 31 func1 (last_name = 'walsh', first_name = 'mikey')
567 59 /tmp/scr5.py
568 -------------------------------------------------------------------------
569
570 Description of arguments:
571 indent The number of characters to indent each
572 line of output.
573 stack_frame_ix The index of the first stack frame which
574 is to be returned.
575 """
576
577 buffer = ""
578
579 buffer += sprint_dashes()
580 buffer += "Python function call stack\n\n"
581 buffer += "Line # Function name and arguments\n"
582 buffer += sprint_dashes(0, 6, 0) + " " + sprint_dashes(0, 73)
583
584 # Grab the current program stack.
585 current_stack = inspect.stack()
586
587 # Process each frame in turn.
588 format_string = "%6s %s\n"
589 for stack_frame in current_stack:
590 lineno = str(stack_frame[2])
591 func_name = str(stack_frame[3])
592 if func_name == "?":
593 # "?" is the name used when code is not in a function.
594 func_name = "(none)"
595
596 if func_name == "<module>":
597 # If the func_name is the "main" program, we simply get the command
598 # line call string.
599 func_and_args = ' '.join(sys.argv)
600 else:
601 # Get the program arguments.
602 arg_vals = inspect.getargvalues(stack_frame[0])
603 function_parms = arg_vals[0]
604 frame_locals = arg_vals[3]
605
606 args_arr = []
607 for arg_name in function_parms:
608 # Get the arg value from frame locals.
609 arg_value = frame_locals[arg_name]
610 args_arr.append(arg_name + " = " + repr(arg_value))
611 args_str = "(" + ', '.join(map(str, args_arr)) + ")"
612
613 # Now we need to print this in a nicely-wrapped way.
614 func_and_args = func_name + " " + args_str
615
616 buffer += format_string % (lineno, func_and_args)
617
618 buffer += sprint_dashes()
619
620 return buffer
621
622###############################################################################
623
624
625###############################################################################
626def sprint_executing(stack_frame_ix=None):
627
628 r"""
629 Print a line indicating what function is executing and with what parameter
630 values. This is useful for debugging.
631
632 Sample output:
633
634 #(CDT) 2016/08/25 17:54:27 - Executing: func1 (x = 1)
635
636 Description of arguments:
637 stack_frame_ix The index of the stack frame whose
638 function info should be returned. If the
639 caller does not specifiy a value, this
640 function will set the value to 1 which is
641 the index of the caller's stack frame. If
642 the caller is the wrapper function
643 "print_executing", this function will bump
644 it up by 1.
645 """
646
647 # If user wants default stack_frame_ix.
648 if stack_frame_ix is None:
649 func_name = sys._getframe().f_code.co_name
650 caller_func_name = sys._getframe(1).f_code.co_name
651 if func_name[1:] == caller_func_name:
652 stack_frame_ix = 2
653 else:
654 stack_frame_ix = 1
655
656 stack_frame = inspect.stack()[stack_frame_ix]
657
658 func_name = str(stack_frame[3])
659 if func_name == "?":
660 # "?" is the name used when code is not in a function.
661 func_name = "(none)"
662
663 if func_name == "<module>":
664 # If the func_name is the "main" program, we simply get the command
665 # line call string.
666 func_and_args = ' '.join(sys.argv)
667 else:
668 # Get the program arguments.
669 arg_vals = inspect.getargvalues(stack_frame[0])
670 function_parms = arg_vals[0]
671 frame_locals = arg_vals[3]
672
673 args_arr = []
674 for arg_name in function_parms:
675 # Get the arg value from frame locals.
676 arg_value = frame_locals[arg_name]
677 args_arr.append(arg_name + " = " + repr(arg_value))
678 args_str = "(" + ', '.join(map(str, args_arr)) + ")"
679
680 # Now we need to print this in a nicely-wrapped way.
681 func_and_args = func_name + " " + args_str
682
683 return sprint_time() + "Executing: " + func_and_args + "\n"
684
685###############################################################################
686
687
688###############################################################################
689def sprint_pgm_header():
690
691 r"""
692 Return a standardized header that programs should print at the beginning
693 of the run. It includes useful information like command line, pid,
694 userid, program parameters, etc.
695
696 """
697
698 buffer = "\n"
699 buffer += sprint_time() + "Running " + pgm_name + ".\n"
700 buffer += sprint_time() + "Program parameter values, etc.:\n\n"
701 buffer += sprint_varx("command_line", ' '.join(sys.argv))
702 # We want the output to show a customized name for the pid and pgid but we
703 # want it to look like a valid variable name. Therefore, we'll use
704 # pgm_name_var_name which was set when this module was imported.
705 buffer += sprint_varx(pgm_name_var_name + "_pid", os.getpid())
706 buffer += sprint_varx(pgm_name_var_name + "_pgid", os.getpgrp())
707 buffer += sprint_varx("uid", str(os.geteuid()) + " (" + os.getlogin() +
708 ")")
709 buffer += sprint_varx("gid", str(os.getgid()) + " (" +
710 str(grp.getgrgid(os.getgid()).gr_name) + ")")
711 buffer += sprint_varx("host_name", socket.gethostname())
712 buffer += sprint_varx("DISPLAY", os.environ['DISPLAY'])
713 # I want to add code to print caller's parms.
714
715 buffer += "\n"
716
717 return buffer
718
719###############################################################################
720
721
722###############################################################################
723def sissuing(cmd_buf):
724
725 r"""
726 Return a line indicating a command that the program is about to execute.
727
728 Sample output for a cmd_buf of "ls"
729
730 #(CDT) 2016/08/25 17:57:36 - Issuing: ls
731 Description of args:
732 cmd_buf The command to be executed by caller.
733 """
734
735 buffer = sprint_time() + "Issuing: " + cmd_buf + "\n"
736
737 return buffer
738
739###############################################################################
740
741
742###############################################################################
743def sprint_pgm_footer():
744
745 r"""
746 Return a standardized footer that programs should print at the end of the
747 program run. It includes useful information like total run time, etc.
748 """
749
750 buffer = "\n" + sprint_time() + "Finished running " + pgm_name + ".\n\n"
751
752 total_time = time.time() - start_time
753 total_time_string = "%0.6f" % total_time
754
755 buffer += sprint_varx(pgm_name_var_name + "runtime", total_time_string)
756
757 return buffer
758
759###############################################################################
760
761
762###############################################################################
763# In the following section of code, we will dynamically create print versions
764# for each of the sprint functions defined above. So, for example, where we
765# have an sprint_time() function defined above that returns the time to the
766# caller in a string, we will create a corresponding print_time() function that
767# will print that string directly to stdout.
768
769# It can be complicated to follow what's being creaed by the exec statement
770# below. Here is an example of the print_time() function that will be created:
771
772# def print_time(*args):
773# s_funcname = "s" + sys._getframe().f_code.co_name
774# s_func = getattr(sys.modules[__name__], s_funcname)
775# sys.stdout.write(s_func(*args))
776
777# Here are comments describing the 3 lines in the body of the created function.
778# Calculate the "s" version of this function name (e.g. if this function name
779# is print_time, we want s_funcname to be "sprint_time".
780# Put a reference to the "s" version of this function in s_func.
781# Call the "s" version of this function passing it all of our arguments. Write
782# the result to stdout.
783
784# func_names contains a list of all print functions which should be created
785# from their sprint counterparts.
786func_names = ['print_time', 'print_timen', 'print_error', 'print_varx',
787 'print_var', 'print_dashes', 'print_call_stack',
788 'print_func_name', 'print_executing', 'print_pgm_header',
789 'issuing', 'print_pgm_footer']
790
791for func_name in func_names:
792 # Create abbreviated aliases (e.g. spvar is an alias for sprint_var).
793 alias = re.sub("print_", "p", func_name)
794 exec("s" + alias + " = s" + func_name)
795
796for func_name in func_names:
797 if func_name == "print_error":
798 output_stream = "stderr"
799 else:
800 output_stream = "stdout"
801 func_def = \
802 [
803 "def " + func_name + "(*args):",
804 " s_func_name = \"s\" + sys._getframe().f_code.co_name",
805 " s_func = getattr(sys.modules[__name__], s_func_name)",
806 " sys." + output_stream + ".write(s_func(*args))",
807 " sys." + output_stream + ".flush()"
808 ]
809 pgm_definition_string = '\n'.join(func_def)
810 exec(pgm_definition_string)
811
812 # Create abbreviated aliases (e.g. pvar is an alias for print_var).
813 alias = re.sub("print_", "p", func_name)
814 exec(alias + " = " + func_name)
815
816###############################################################################