blob: 9aedfaade54bd9939f2d7d60fc7720ab01a3f5ae [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 Walshde791732016-09-06 14:25:24 -050029###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -050030def rprint(buffer="",
31 stream="STDOUT"):
Michael Walshde791732016-09-06 14:25:24 -050032
33 r"""
34 rprint stands for "Robot Print". This keyword will print the user's
35 buffer to the console. This keyword does not write a linefeed. It is the
36 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -060037 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -050038
39 Description of arguments:
40 buffer The value that is to written to stdout.
41 """
42
Michael Walsh82acf002017-05-04 14:33:05 -050043 BuiltIn().log_to_console(gp.replace_passwords(str(buffer)),
44 no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050045
46###############################################################################
47
48
49###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -050050def rprintn(buffer="",
51 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -050052
53 r"""
54 rprintn stands for "Robot print with linefeed". This keyword will print
55 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -050056 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -050057
58 Description of arguments:
59 buffer The value that is to written to stdout.
60 """
61
Michael Walsh82acf002017-05-04 14:33:05 -050062 BuiltIn().log_to_console(gp.replace_passwords(buffer), no_newline=False,
63 stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050064
65###############################################################################
66
67
68###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -060069def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -050070
71 r"""
Michael Walsh18176322016-11-15 15:11:21 -060072 sprint_vars stands for "String Print Vars". This is a robot redefinition
73 of the sprint_vars function in gen_print.py. Given a list of variable
74 names, this keyword will string print each variable name and value such
75 that the value lines up in the same column as messages printed with rptime.
76
77 Description of arguments:
78 args:
79 If the first argument is an integer, it will be interpreted to be the
Michael Walsh18176322016-11-15 15:11:21 -060080 "hex" value.
Michael Walshc4da0cb2017-01-10 11:31:05 -060081 If the second argument is an integer, it will be interpreted to be the
82 "indent" value.
83 If the third argument is an integer, it will be interpreted to be the
84 "col1_width" value.
Michael Walsh18176322016-11-15 15:11:21 -060085 All remaining parms are considered variable names which are to be
86 sprinted.
87 """
88
89 if len(args) == 0:
90 return
91
92 # Create list from args (which is a tuple) so that it can be modified.
93 args_list = list(args)
94
Michael Walshc4da0cb2017-01-10 11:31:05 -060095 # See if parm 1 is to be interpreted as "hex".
96 try:
97 if type(int(args_list[0])) is int:
98 hex = int(args_list[0])
99 args_list.pop(0)
100 except ValueError:
101 hex = 0
102
103 # See if parm 2 is to be interpreted as "indent".
Michael Walsh18176322016-11-15 15:11:21 -0600104 try:
105 if type(int(args_list[0])) is int:
106 indent = int(args_list[0])
107 args_list.pop(0)
108 except ValueError:
109 indent = 0
110
Michael Walshc4da0cb2017-01-10 11:31:05 -0600111 # See if parm 3 is to be interpreted as "col1_width".
Michael Walsh18176322016-11-15 15:11:21 -0600112 try:
113 if type(int(args_list[0])) is int:
114 loc_col1_width = int(args_list[0])
115 args_list.pop(0)
116 except ValueError:
117 loc_col1_width = gp.col1_width
118
Michael Walsh18176322016-11-15 15:11:21 -0600119 buffer = ""
120 for var_name in args_list:
Michael Walsh0fa47622017-02-20 16:11:34 -0600121 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}")
Michael Walsh18176322016-11-15 15:11:21 -0600122 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
123 loc_col1_width)
124
125 return buffer
126
127###############################################################################
128
129
130###############################################################################
131def sprint_pgm_header(indent=0):
132
133 r"""
134 Sprint a standardized header that robot programs should print at the
135 beginning of the run. The header includes useful information like command
136 line, pid, userid, program parameters, etc. Callers need to have declared
137 a global @{parm_list} variable which contains the names of all program
138 parameters.
139 """
140
Michael Walshdb6e68a2017-05-23 17:55:31 -0500141 # This function is deprecated since the caller may now call the gen_print
142 # version directly.
143 return gp.sprint_pgm_header(indent, linefeed=1)
Michael Walsh18176322016-11-15 15:11:21 -0600144
145###############################################################################
146
147
148###############################################################################
149def sprint_error_report(error_text="\n"):
150
151 r"""
152 Print a standardized error report that robot programs should print on
153 failure. The report includes useful information like error text, command
154 line, pid, userid, program parameters, etc. Callers must have declared a
155 @{parm_list} variable which contains the names of all program parameters.
156 """
157
Michael Walshdb6e68a2017-05-23 17:55:31 -0500158 # This function is deprecated. The caller is advised to call the
159 # gen_print version of this function directly.
Michael Walshafa7a1b2016-12-09 14:02:48 -0600160
Michael Walshdb6e68a2017-05-23 17:55:31 -0500161 return gp.sprint_error_report(error_text)
Michael Walsh18176322016-11-15 15:11:21 -0600162
163###############################################################################
164
165
166###############################################################################
167def sprint_issuing_keyword(cmd_buf,
168 test_mode=0):
169
170 r"""
171 Return a line indicating a robot command (i.e. keyword + args) that the
172 program is about to execute.
173
174 For example, for the following robot code...
175
176 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
177 rdprint_issuing_keyword
178
179 The output would look something like this:
180
181 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
182
183 Description of args:
184 cmd_buf A list containing the keyword and
185 arguments to be run.
186 """
187
188 buffer = ""
189 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
190 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
191
192 return buffer
193
194###############################################################################
195
196
197###############################################################################
198def sprint_auto_vars(headers=0):
199
200 r"""
201 This keyword will string print all of the Automatic Variables described in
202 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500203
204 NOTE: Not all automatic variables are guaranteed to exist.
205
206 Description of arguments:
207 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600208 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500209 """
210
Michael Walsh18176322016-11-15 15:11:21 -0600211 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500212 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600213 buffer += gp.sprint_dashes()
214 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500215
Michael Walsh18176322016-11-15 15:11:21 -0600216 buffer += \
217 sprint_vars(
218 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
219 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
220 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
221 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
222 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
223 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
224 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500225
226 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600227 buffer += gp.sprint_dashes()
228
229 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500230
231###############################################################################
232
233
234###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600235# In the following section of code, we will dynamically create robot versions
236# of print functions for each of the sprint functions defined in the
237# gen_print.py module. So, for example, where we have an sprint_time()
238# function defined above that returns the time to the caller in a string, we
239# will create a corresponding rprint_time() function that will print that
240# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500241
Michael Walsh18176322016-11-15 15:11:21 -0600242# It can be complicated to follow what's being created by the exec statement
243# below. Here is an example of the rprint_time() function that will be
244# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500245
Michael Walsh18176322016-11-15 15:11:21 -0600246# def rprint_time(*args):
247# s_func = getattr(gp, "sprint_time")
248# BuiltIn().log_to_console(s_func(*args),
249# stream='STDIN',
250# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500251
Michael Walsh18176322016-11-15 15:11:21 -0600252# Here are comments describing the lines in the body of the created function.
253# Put a reference to the "s" version of this function in s_func.
254# Call the "s" version of this function passing it all of our arguments. Log
255# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500256
Michael Walsh18176322016-11-15 15:11:21 -0600257robot_prefix = "r"
258robot_func_names =\
259 [
260 'print_error_report', 'print_pgm_header',
261 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
262 ]
263func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600264
Michael Walshafa7a1b2016-12-09 14:02:48 -0600265explicit_definitions = ['print', 'printn']
266
Michael Walsha6723f22016-11-22 11:12:01 -0600267func_names = list(my_ord_dict.fromkeys(func_names))
268
269if gen_robot_print_debug:
270 rprintn()
271 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
272 rprintn()
273
Michael Walsh18176322016-11-15 15:11:21 -0600274for func_name in func_names:
Michael Walshde791732016-09-06 14:25:24 -0500275
Michael Walshafa7a1b2016-12-09 14:02:48 -0600276 if func_name not in explicit_definitions:
277 # The print_var function's job is to figure out the name of arg 1 and
278 # then call print_varx. This is not currently supported for robot
279 # programs. Though it IS supported for python modules.
280 if func_name == "print_error" or func_name == "print_error_report":
281 output_stream = "STDERR"
282 else:
283 output_stream = "STDIN"
284 if func_name in robot_func_names:
285 object_name = "__import__(__name__)"
286 else:
287 object_name = "gp"
288 func_def = \
289 [
290 "def " + robot_prefix + func_name + "(*args):",
291 " s_func = getattr(" + object_name + ", \"s" + func_name +
292 "\")",
Michael Walsh82acf002017-05-04 14:33:05 -0500293 " BuiltIn().log_to_console" +
294 "(gp.replace_passwords(s_func(*args)),"
Michael Walshafa7a1b2016-12-09 14:02:48 -0600295 " stream='" + output_stream + "',"
296 " no_newline=True)"
297 ]
298
299 pgm_definition_string = '\n'.join(func_def)
300 if gen_robot_print_debug:
301 rprintn()
302 rprintn(pgm_definition_string)
303 exec(pgm_definition_string)
Michael Walsh18176322016-11-15 15:11:21 -0600304
305 # Now define "q" versions of each print function. The q functions only
306 # print if global robot var "quiet" is 0. If the global var quiet is not
307 # defined, it will be treated as though it were "1", i.e. no printing will
308 # be done.
309 func_def = \
310 [
311 "def rq" + func_name + "(*args):",
Michael Walshf897bcf2017-09-06 17:15:41 -0500312 " if int(gp.get_var_value(None, 0, \"quiet\")): return",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600313 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600314 ]
315
316 pgm_definition_string = '\n'.join(func_def)
317 if gen_robot_print_debug:
318 rprintn(pgm_definition_string)
319 exec(pgm_definition_string)
320
321 # Now define "d" versions of each print function. The d functions only
322 # print if global robot var "debug" is 1.
323 func_def = \
324 [
325 "def rd" + func_name + "(*args):",
Michael Walshf897bcf2017-09-06 17:15:41 -0500326 " if not int(gp.get_var_value(None, 0, \"debug\")): return",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600327 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600328 ]
329
330 pgm_definition_string = '\n'.join(func_def)
331 if gen_robot_print_debug:
332 rprintn(pgm_definition_string)
333 exec(pgm_definition_string)
334
Michael Walshafa7a1b2016-12-09 14:02:48 -0600335 # Create shorter aliases.
Michael Walsha6723f22016-11-22 11:12:01 -0600336 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600337 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600338 for prefix2 in prefixes:
339 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
340 prefix2 + func_name
341 if gen_robot_print_debug:
342 rprintn(cmd_buf)
343 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600344
345# Define an alias. rpvar is just a special case of rpvars where the args
346# list contains only one element.
347cmd_buf = "rpvar = rpvars"
348if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600349 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600350 rprintn(cmd_buf)
351exec(cmd_buf)
Michael Walshde791732016-09-06 14:25:24 -0500352
353###############################################################################