blob: 7d4e7cbf51dff79276001fc93456e7f452587088 [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
32 r"""
33 rprint stands for "Robot Print". This keyword will print the user's
34 buffer to the console. This keyword does not write a linefeed. It is the
35 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -060036 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -050037
38 Description of arguments:
39 buffer The value that is to written to stdout.
40 """
41
Michael Walsh82acf002017-05-04 14:33:05 -050042 BuiltIn().log_to_console(gp.replace_passwords(str(buffer)),
43 no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050044
Michael Walshde791732016-09-06 14:25:24 -050045
Michael Walsh7423c012016-10-04 10:27:21 -050046def rprintn(buffer="",
47 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -050048
49 r"""
50 rprintn stands for "Robot print with linefeed". This keyword will print
51 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -050052 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -050053
54 Description of arguments:
55 buffer The value that is to written to stdout.
56 """
57
Michael Walsh82acf002017-05-04 14:33:05 -050058 BuiltIn().log_to_console(gp.replace_passwords(buffer), no_newline=False,
59 stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050060
Michael Walshde791732016-09-06 14:25:24 -050061
Michael Walsh18176322016-11-15 15:11:21 -060062def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -050063
64 r"""
Michael Walsh18176322016-11-15 15:11:21 -060065 sprint_vars stands for "String Print Vars". This is a robot redefinition
66 of the sprint_vars function in gen_print.py. Given a list of variable
67 names, this keyword will string print each variable name and value such
68 that the value lines up in the same column as messages printed with rptime.
69
70 Description of arguments:
71 args:
72 If the first argument is an integer, it will be interpreted to be the
Michael Walsh18176322016-11-15 15:11:21 -060073 "hex" value.
Michael Walshc4da0cb2017-01-10 11:31:05 -060074 If the second argument is an integer, it will be interpreted to be the
75 "indent" value.
76 If the third argument is an integer, it will be interpreted to be the
77 "col1_width" value.
Michael Walsh18176322016-11-15 15:11:21 -060078 All remaining parms are considered variable names which are to be
79 sprinted.
80 """
81
82 if len(args) == 0:
83 return
84
85 # Create list from args (which is a tuple) so that it can be modified.
86 args_list = list(args)
87
Michael Walshc4da0cb2017-01-10 11:31:05 -060088 # See if parm 1 is to be interpreted as "hex".
89 try:
90 if type(int(args_list[0])) is int:
91 hex = int(args_list[0])
92 args_list.pop(0)
93 except ValueError:
94 hex = 0
95
96 # See if parm 2 is to be interpreted as "indent".
Michael Walsh18176322016-11-15 15:11:21 -060097 try:
98 if type(int(args_list[0])) is int:
99 indent = int(args_list[0])
100 args_list.pop(0)
101 except ValueError:
102 indent = 0
103
Michael Walshc4da0cb2017-01-10 11:31:05 -0600104 # See if parm 3 is to be interpreted as "col1_width".
Michael Walsh18176322016-11-15 15:11:21 -0600105 try:
106 if type(int(args_list[0])) is int:
107 loc_col1_width = int(args_list[0])
108 args_list.pop(0)
109 except ValueError:
110 loc_col1_width = gp.col1_width
111
Michael Walsh18176322016-11-15 15:11:21 -0600112 buffer = ""
113 for var_name in args_list:
Michael Walsh0fa47622017-02-20 16:11:34 -0600114 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}")
Michael Walsh18176322016-11-15 15:11:21 -0600115 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
116 loc_col1_width)
117
118 return buffer
119
Michael Walsh18176322016-11-15 15:11:21 -0600120
Michael Walsh18176322016-11-15 15:11:21 -0600121def sprint_pgm_header(indent=0):
122
123 r"""
124 Sprint a standardized header that robot programs should print at the
125 beginning of the run. The header includes useful information like command
126 line, pid, userid, program parameters, etc. Callers need to have declared
127 a global @{parm_list} variable which contains the names of all program
128 parameters.
129 """
130
Michael Walshdb6e68a2017-05-23 17:55:31 -0500131 # This function is deprecated since the caller may now call the gen_print
132 # version directly.
133 return gp.sprint_pgm_header(indent, linefeed=1)
Michael Walsh18176322016-11-15 15:11:21 -0600134
Michael Walsh18176322016-11-15 15:11:21 -0600135
Michael Walsh18176322016-11-15 15:11:21 -0600136def sprint_error_report(error_text="\n"):
137
138 r"""
139 Print a standardized error report that robot programs should print on
140 failure. The report includes useful information like error text, command
141 line, pid, userid, program parameters, etc. Callers must have declared a
142 @{parm_list} variable which contains the names of all program parameters.
143 """
144
Michael Walshdb6e68a2017-05-23 17:55:31 -0500145 # This function is deprecated. The caller is advised to call the
146 # gen_print version of this function directly.
Michael Walshafa7a1b2016-12-09 14:02:48 -0600147
Michael Walshdb6e68a2017-05-23 17:55:31 -0500148 return gp.sprint_error_report(error_text)
Michael Walsh18176322016-11-15 15:11:21 -0600149
Michael Walsh18176322016-11-15 15:11:21 -0600150
Michael Walsh18176322016-11-15 15:11:21 -0600151def sprint_issuing_keyword(cmd_buf,
152 test_mode=0):
153
154 r"""
155 Return a line indicating a robot command (i.e. keyword + args) that the
156 program is about to execute.
157
158 For example, for the following robot code...
159
160 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
161 rdprint_issuing_keyword
162
163 The output would look something like this:
164
165 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
166
167 Description of args:
168 cmd_buf A list containing the keyword and
169 arguments to be run.
170 """
171
172 buffer = ""
173 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
174 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
175
176 return buffer
177
Michael Walsh18176322016-11-15 15:11:21 -0600178
Michael Walsh18176322016-11-15 15:11:21 -0600179def sprint_auto_vars(headers=0):
180
181 r"""
182 This keyword will string print all of the Automatic Variables described in
183 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500184
185 NOTE: Not all automatic variables are guaranteed to exist.
186
187 Description of arguments:
188 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600189 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500190 """
191
Michael Walsh18176322016-11-15 15:11:21 -0600192 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500193 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600194 buffer += gp.sprint_dashes()
195 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500196
Michael Walsh18176322016-11-15 15:11:21 -0600197 buffer += \
198 sprint_vars(
199 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
200 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
201 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
202 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
203 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
204 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
205 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500206
207 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600208 buffer += gp.sprint_dashes()
209
210 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500211
Michael Walshde791732016-09-06 14:25:24 -0500212
Michael Walsh18176322016-11-15 15:11:21 -0600213# In the following section of code, we will dynamically create robot versions
214# of print functions for each of the sprint functions defined in the
215# gen_print.py module. So, for example, where we have an sprint_time()
216# function defined above that returns the time to the caller in a string, we
217# will create a corresponding rprint_time() function that will print that
218# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500219
Michael Walsh18176322016-11-15 15:11:21 -0600220# It can be complicated to follow what's being created by the exec statement
221# below. Here is an example of the rprint_time() function that will be
222# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500223
Michael Walsh18176322016-11-15 15:11:21 -0600224# def rprint_time(*args):
225# s_func = getattr(gp, "sprint_time")
226# BuiltIn().log_to_console(s_func(*args),
227# stream='STDIN',
228# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500229
Michael Walsh18176322016-11-15 15:11:21 -0600230# Here are comments describing the lines in the body of the created function.
231# Put a reference to the "s" version of this function in s_func.
232# Call the "s" version of this function passing it all of our arguments. Log
233# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500234
Michael Walsh18176322016-11-15 15:11:21 -0600235robot_prefix = "r"
236robot_func_names =\
237 [
238 'print_error_report', 'print_pgm_header',
239 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
240 ]
241func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600242
Michael Walshafa7a1b2016-12-09 14:02:48 -0600243explicit_definitions = ['print', 'printn']
244
Michael Walsha6723f22016-11-22 11:12:01 -0600245func_names = list(my_ord_dict.fromkeys(func_names))
246
247if gen_robot_print_debug:
248 rprintn()
249 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
250 rprintn()
251
Michael Walsh18176322016-11-15 15:11:21 -0600252for func_name in func_names:
Michael Walshde791732016-09-06 14:25:24 -0500253
Michael Walshafa7a1b2016-12-09 14:02:48 -0600254 if func_name not in explicit_definitions:
255 # The print_var function's job is to figure out the name of arg 1 and
256 # then call print_varx. This is not currently supported for robot
257 # programs. Though it IS supported for python modules.
258 if func_name == "print_error" or func_name == "print_error_report":
259 output_stream = "STDERR"
260 else:
261 output_stream = "STDIN"
262 if func_name in robot_func_names:
263 object_name = "__import__(__name__)"
264 else:
265 object_name = "gp"
266 func_def = \
267 [
268 "def " + robot_prefix + func_name + "(*args):",
269 " s_func = getattr(" + object_name + ", \"s" + func_name +
270 "\")",
Michael Walsh82acf002017-05-04 14:33:05 -0500271 " BuiltIn().log_to_console" +
272 "(gp.replace_passwords(s_func(*args)),"
Michael Walshafa7a1b2016-12-09 14:02:48 -0600273 " stream='" + output_stream + "',"
274 " no_newline=True)"
275 ]
276
277 pgm_definition_string = '\n'.join(func_def)
278 if gen_robot_print_debug:
279 rprintn()
280 rprintn(pgm_definition_string)
281 exec(pgm_definition_string)
Michael Walsh18176322016-11-15 15:11:21 -0600282
283 # Now define "q" versions of each print function. The q functions only
284 # print if global robot var "quiet" is 0. If the global var quiet is not
285 # defined, it will be treated as though it were "1", i.e. no printing will
286 # be done.
287 func_def = \
288 [
289 "def rq" + func_name + "(*args):",
Michael Walshf897bcf2017-09-06 17:15:41 -0500290 " if int(gp.get_var_value(None, 0, \"quiet\")): return",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600291 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600292 ]
293
294 pgm_definition_string = '\n'.join(func_def)
295 if gen_robot_print_debug:
296 rprintn(pgm_definition_string)
297 exec(pgm_definition_string)
298
299 # Now define "d" versions of each print function. The d functions only
300 # print if global robot var "debug" is 1.
301 func_def = \
302 [
303 "def rd" + func_name + "(*args):",
Michael Walshf897bcf2017-09-06 17:15:41 -0500304 " if not int(gp.get_var_value(None, 0, \"debug\")): return",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600305 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600306 ]
307
308 pgm_definition_string = '\n'.join(func_def)
309 if gen_robot_print_debug:
310 rprintn(pgm_definition_string)
311 exec(pgm_definition_string)
312
Michael Walshafa7a1b2016-12-09 14:02:48 -0600313 # Create shorter aliases.
Michael Walsha6723f22016-11-22 11:12:01 -0600314 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600315 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600316 for prefix2 in prefixes:
317 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
318 prefix2 + func_name
319 if gen_robot_print_debug:
320 rprintn(cmd_buf)
321 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600322
323# Define an alias. rpvar is just a special case of rpvars where the args
324# list contains only one element.
325cmd_buf = "rpvar = rpvars"
326if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600327 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600328 rprintn(cmd_buf)
329exec(cmd_buf)