blob: 4430865964dbe8cbf463906de35ab3530aa31b1f [file] [log] [blame]
Michael Walshde791732016-09-06 14:25:24 -05001#!/usr/bin/env python
2
3r"""
4This file contains functions useful for printing to stdout from robot programs.
5"""
6
7import sys
8import re
Michael Walsh18176322016-11-15 15:11:21 -06009import os
Michael Walsh7423c012016-10-04 10:27:21 -050010
Michael Walsha6723f22016-11-22 11:12:01 -060011try:
12 from robot.utils import DotDict as my_ord_dict
13except ImportError:
14 from collections import OrderedDict as my_ord_dict
15
Michael Walshde791732016-09-06 14:25:24 -050016import gen_print as gp
Michael Walsh7423c012016-10-04 10:27:21 -050017
Michael Walshde791732016-09-06 14:25:24 -050018from robot.libraries.BuiltIn import BuiltIn
19from robot.api import logger
20
Michael Walsh18176322016-11-15 15:11:21 -060021try:
22 # The user can set environment variable "GEN_ROBOT_PRINT_DEBUG" to get
23 # debug output from this module.
Michael Walsha6723f22016-11-22 11:12:01 -060024 gen_robot_print_debug = int(os.environ['GEN_ROBOT_PRINT_DEBUG'])
Michael Walsh18176322016-11-15 15:11:21 -060025except KeyError:
26 gen_robot_print_debug = 0
27
28
Michael Walsh7423c012016-10-04 10:27:21 -050029def rprint(buffer="",
30 stream="STDOUT"):
Michael Walshde791732016-09-06 14:25:24 -050031 r"""
32 rprint stands for "Robot Print". This keyword will print the user's
33 buffer to the console. This keyword does not write a linefeed. It is the
34 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -060035 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -050036
37 Description of arguments:
38 buffer The value that is to written to stdout.
39 """
40
Michael Walsh82acf002017-05-04 14:33:05 -050041 BuiltIn().log_to_console(gp.replace_passwords(str(buffer)),
42 no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050043
Michael Walshde791732016-09-06 14:25:24 -050044
Michael Walsh7423c012016-10-04 10:27:21 -050045def rprintn(buffer="",
46 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -050047 r"""
48 rprintn stands for "Robot print with linefeed". This keyword will print
49 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -050050 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -050051
52 Description of arguments:
53 buffer The value that is to written to stdout.
54 """
55
Michael Walsh82acf002017-05-04 14:33:05 -050056 BuiltIn().log_to_console(gp.replace_passwords(buffer), no_newline=False,
57 stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050058
Michael Walshde791732016-09-06 14:25:24 -050059
Michael Walsh18176322016-11-15 15:11:21 -060060def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -050061 r"""
Michael Walsh18176322016-11-15 15:11:21 -060062 sprint_vars stands for "String Print Vars". This is a robot redefinition
63 of the sprint_vars function in gen_print.py. Given a list of variable
64 names, this keyword will string print each variable name and value such
65 that the value lines up in the same column as messages printed with rptime.
66
67 Description of arguments:
68 args:
69 If the first argument is an integer, it will be interpreted to be the
Michael Walsh18176322016-11-15 15:11:21 -060070 "hex" value.
Michael Walshc4da0cb2017-01-10 11:31:05 -060071 If the second argument is an integer, it will be interpreted to be the
72 "indent" value.
73 If the third argument is an integer, it will be interpreted to be the
74 "col1_width" value.
Michael Walsh18176322016-11-15 15:11:21 -060075 All remaining parms are considered variable names which are to be
76 sprinted.
77 """
78
79 if len(args) == 0:
80 return
81
82 # Create list from args (which is a tuple) so that it can be modified.
83 args_list = list(args)
84
Michael Walshc4da0cb2017-01-10 11:31:05 -060085 # See if parm 1 is to be interpreted as "hex".
86 try:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050087 if isinstance(int(args_list[0]), int):
Michael Walshc4da0cb2017-01-10 11:31:05 -060088 hex = int(args_list[0])
89 args_list.pop(0)
90 except ValueError:
91 hex = 0
92
93 # See if parm 2 is to be interpreted as "indent".
Michael Walsh18176322016-11-15 15:11:21 -060094 try:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050095 if isinstance(int(args_list[0]), int):
Michael Walsh18176322016-11-15 15:11:21 -060096 indent = int(args_list[0])
97 args_list.pop(0)
98 except ValueError:
99 indent = 0
100
Michael Walshc4da0cb2017-01-10 11:31:05 -0600101 # See if parm 3 is to be interpreted as "col1_width".
Michael Walsh18176322016-11-15 15:11:21 -0600102 try:
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500103 if isinstance(int(args_list[0]), int):
Michael Walsh18176322016-11-15 15:11:21 -0600104 loc_col1_width = int(args_list[0])
105 args_list.pop(0)
106 except ValueError:
107 loc_col1_width = gp.col1_width
108
Michael Walsh18176322016-11-15 15:11:21 -0600109 buffer = ""
110 for var_name in args_list:
Michael Walsh0fa47622017-02-20 16:11:34 -0600111 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}")
Michael Walsh18176322016-11-15 15:11:21 -0600112 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
113 loc_col1_width)
114
115 return buffer
116
Michael Walsh18176322016-11-15 15:11:21 -0600117
Michael Walsh18176322016-11-15 15:11:21 -0600118def sprint_pgm_header(indent=0):
Michael Walsh18176322016-11-15 15:11:21 -0600119 r"""
120 Sprint a standardized header that robot programs should print at the
121 beginning of the run. The header includes useful information like command
122 line, pid, userid, program parameters, etc. Callers need to have declared
123 a global @{parm_list} variable which contains the names of all program
124 parameters.
125 """
126
Michael Walshdb6e68a2017-05-23 17:55:31 -0500127 # This function is deprecated since the caller may now call the gen_print
128 # version directly.
129 return gp.sprint_pgm_header(indent, linefeed=1)
Michael Walsh18176322016-11-15 15:11:21 -0600130
Michael Walsh18176322016-11-15 15:11:21 -0600131
Michael Walsh18176322016-11-15 15:11:21 -0600132def sprint_error_report(error_text="\n"):
Michael Walsh18176322016-11-15 15:11:21 -0600133 r"""
134 Print a standardized error report that robot programs should print on
135 failure. The report includes useful information like error text, command
136 line, pid, userid, program parameters, etc. Callers must have declared a
137 @{parm_list} variable which contains the names of all program parameters.
138 """
139
Michael Walshdb6e68a2017-05-23 17:55:31 -0500140 # This function is deprecated. The caller is advised to call the
141 # gen_print version of this function directly.
Michael Walshafa7a1b2016-12-09 14:02:48 -0600142
Michael Walshdb6e68a2017-05-23 17:55:31 -0500143 return gp.sprint_error_report(error_text)
Michael Walsh18176322016-11-15 15:11:21 -0600144
Michael Walsh18176322016-11-15 15:11:21 -0600145
Michael Walsh18176322016-11-15 15:11:21 -0600146def sprint_issuing_keyword(cmd_buf,
147 test_mode=0):
Michael Walsh18176322016-11-15 15:11:21 -0600148 r"""
149 Return a line indicating a robot command (i.e. keyword + args) that the
150 program is about to execute.
151
152 For example, for the following robot code...
153
154 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
155 rdprint_issuing_keyword
156
157 The output would look something like this:
158
159 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
160
161 Description of args:
162 cmd_buf A list containing the keyword and
163 arguments to be run.
164 """
165
166 buffer = ""
167 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
168 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
169
170 return buffer
171
Michael Walsh18176322016-11-15 15:11:21 -0600172
Michael Walsh18176322016-11-15 15:11:21 -0600173def sprint_auto_vars(headers=0):
Michael Walsh18176322016-11-15 15:11:21 -0600174 r"""
175 This keyword will string print all of the Automatic Variables described in
176 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500177
178 NOTE: Not all automatic variables are guaranteed to exist.
179
180 Description of arguments:
181 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600182 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500183 """
184
Michael Walsh18176322016-11-15 15:11:21 -0600185 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500186 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600187 buffer += gp.sprint_dashes()
188 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500189
Michael Walsh18176322016-11-15 15:11:21 -0600190 buffer += \
191 sprint_vars(
192 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
193 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
194 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
195 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
196 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
197 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
198 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500199
200 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600201 buffer += gp.sprint_dashes()
202
203 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500204
Michael Walshde791732016-09-06 14:25:24 -0500205
Michael Walsh18176322016-11-15 15:11:21 -0600206# In the following section of code, we will dynamically create robot versions
207# of print functions for each of the sprint functions defined in the
208# gen_print.py module. So, for example, where we have an sprint_time()
209# function defined above that returns the time to the caller in a string, we
210# will create a corresponding rprint_time() function that will print that
211# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500212
Michael Walsh18176322016-11-15 15:11:21 -0600213# It can be complicated to follow what's being created by the exec statement
214# below. Here is an example of the rprint_time() function that will be
215# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500216
Michael Walsh18176322016-11-15 15:11:21 -0600217# def rprint_time(*args):
218# s_func = getattr(gp, "sprint_time")
219# BuiltIn().log_to_console(s_func(*args),
220# stream='STDIN',
221# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500222
Michael Walsh18176322016-11-15 15:11:21 -0600223# Here are comments describing the lines in the body of the created function.
224# Put a reference to the "s" version of this function in s_func.
225# Call the "s" version of this function passing it all of our arguments. Log
226# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500227
Michael Walsh18176322016-11-15 15:11:21 -0600228robot_prefix = "r"
229robot_func_names =\
230 [
231 'print_error_report', 'print_pgm_header',
232 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
233 ]
234func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600235
Michael Walshafa7a1b2016-12-09 14:02:48 -0600236explicit_definitions = ['print', 'printn']
237
Michael Walsha6723f22016-11-22 11:12:01 -0600238func_names = list(my_ord_dict.fromkeys(func_names))
239
240if gen_robot_print_debug:
241 rprintn()
242 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
243 rprintn()
244
Michael Walsh18176322016-11-15 15:11:21 -0600245for func_name in func_names:
Michael Walshde791732016-09-06 14:25:24 -0500246
Michael Walshafa7a1b2016-12-09 14:02:48 -0600247 if func_name not in explicit_definitions:
248 # The print_var function's job is to figure out the name of arg 1 and
249 # then call print_varx. This is not currently supported for robot
250 # programs. Though it IS supported for python modules.
251 if func_name == "print_error" or func_name == "print_error_report":
252 output_stream = "STDERR"
253 else:
254 output_stream = "STDIN"
255 if func_name in robot_func_names:
256 object_name = "__import__(__name__)"
257 else:
258 object_name = "gp"
259 func_def = \
260 [
261 "def " + robot_prefix + func_name + "(*args):",
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500262 " s_func = getattr(" + object_name + ", \"s" + func_name
263 + "\")",
264 " BuiltIn().log_to_console"
265 + "(gp.replace_passwords(s_func(*args)),"
Michael Walshafa7a1b2016-12-09 14:02:48 -0600266 " stream='" + output_stream + "',"
267 " no_newline=True)"
268 ]
269
270 pgm_definition_string = '\n'.join(func_def)
271 if gen_robot_print_debug:
272 rprintn()
273 rprintn(pgm_definition_string)
274 exec(pgm_definition_string)
Michael Walsh18176322016-11-15 15:11:21 -0600275
276 # Now define "q" versions of each print function. The q functions only
277 # print if global robot var "quiet" is 0. If the global var quiet is not
278 # defined, it will be treated as though it were "1", i.e. no printing will
279 # be done.
280 func_def = \
281 [
282 "def rq" + func_name + "(*args):",
Michael Walshf897bcf2017-09-06 17:15:41 -0500283 " if int(gp.get_var_value(None, 0, \"quiet\")): return",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600284 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600285 ]
286
287 pgm_definition_string = '\n'.join(func_def)
288 if gen_robot_print_debug:
289 rprintn(pgm_definition_string)
290 exec(pgm_definition_string)
291
292 # Now define "d" versions of each print function. The d functions only
293 # print if global robot var "debug" is 1.
294 func_def = \
295 [
296 "def rd" + func_name + "(*args):",
Michael Walshf897bcf2017-09-06 17:15:41 -0500297 " if not int(gp.get_var_value(None, 0, \"debug\")): return",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600298 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600299 ]
300
301 pgm_definition_string = '\n'.join(func_def)
302 if gen_robot_print_debug:
303 rprintn(pgm_definition_string)
304 exec(pgm_definition_string)
305
Michael Walshafa7a1b2016-12-09 14:02:48 -0600306 # Create shorter aliases.
Michael Walsha6723f22016-11-22 11:12:01 -0600307 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600308 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600309 for prefix2 in prefixes:
310 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
311 prefix2 + func_name
312 if gen_robot_print_debug:
313 rprintn(cmd_buf)
314 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600315
316# Define an alias. rpvar is just a special case of rpvars where the args
317# list contains only one element.
318cmd_buf = "rpvar = rpvars"
319if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600320 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600321 rprintn(cmd_buf)
322exec(cmd_buf)