blob: 8fdd7d09fb5f6cb335a7582e388757dda21925b3 [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 Walshde791732016-09-06 14:25:24 -050011import gen_print as gp
Michael Walsh7423c012016-10-04 10:27:21 -050012
Michael Walshde791732016-09-06 14:25:24 -050013from robot.libraries.BuiltIn import BuiltIn
14from robot.api import logger
15
16
Michael Walsh18176322016-11-15 15:11:21 -060017try:
18 # The user can set environment variable "GEN_ROBOT_PRINT_DEBUG" to get
19 # debug output from this module.
20 gen_robot_print_debug = os.environ['GEN_ROBOT_PRINT_DEBUG']
21except KeyError:
22 gen_robot_print_debug = 0
23
24
Michael Walshde791732016-09-06 14:25:24 -050025###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -060026def set_quiet_default(quiet=None,
27 default=0):
Michael Walshde791732016-09-06 14:25:24 -050028
Michael Walsh18176322016-11-15 15:11:21 -060029 r"""
30 Return a default value for the quiet variable based on its current value,
31 the value of global ${QUIET} and default.
Michael Walshde791732016-09-06 14:25:24 -050032
Michael Walsh18176322016-11-15 15:11:21 -060033 Description of Arguments:
34 quiet If this is set already, no default value
35 is chosen. Otherwise, it will be set to
36 either the global ${QUIET} robot variable
37 or to default (below).
38 default The default value to be used if global
39 ${QUIET} does not exist.
40 """
Michael Walshde791732016-09-06 14:25:24 -050041
Michael Walsh18176322016-11-15 15:11:21 -060042 if quiet is None:
43 # Set default quiet value.
44 try:
45 quiet = int(BuiltIn().get_variable_value("${quiet}"))
46 except TypeError:
47 quiet = int(default)
48 quiet = int(quiet)
Michael Walshde791732016-09-06 14:25:24 -050049
Michael Walsh18176322016-11-15 15:11:21 -060050 return quiet
Michael Walshde791732016-09-06 14:25:24 -050051
52###############################################################################
53
54
55###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -050056def rprint(buffer="",
57 stream="STDOUT"):
Michael Walshde791732016-09-06 14:25:24 -050058
59 r"""
60 rprint stands for "Robot Print". This keyword will print the user's
61 buffer to the console. This keyword does not write a linefeed. It is the
62 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -060063 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -050064
65 Description of arguments:
66 buffer The value that is to written to stdout.
67 """
68
Michael Walsh18176322016-11-15 15:11:21 -060069 BuiltIn().log_to_console(str(buffer), no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050070
71###############################################################################
72
73
74###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -050075def rprintn(buffer="",
76 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -050077
78 r"""
79 rprintn stands for "Robot print with linefeed". This keyword will print
80 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -050081 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -050082
83 Description of arguments:
84 buffer The value that is to written to stdout.
85 """
86
Michael Walsh7423c012016-10-04 10:27:21 -050087 BuiltIn().log_to_console(buffer, no_newline=False, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050088
89###############################################################################
90
91
92###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -060093def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -050094
95 r"""
Michael Walsh18176322016-11-15 15:11:21 -060096 sprint_vars stands for "String Print Vars". This is a robot redefinition
97 of the sprint_vars function in gen_print.py. Given a list of variable
98 names, this keyword will string print each variable name and value such
99 that the value lines up in the same column as messages printed with rptime.
100
101 Description of arguments:
102 args:
103 If the first argument is an integer, it will be interpreted to be the
104 "indent" value.
105 If the second argument is an integer, it will be interpreted to be the
106 "col1_width" value.
107 If the third argument is an integer, it will be interpreted to be the
108 "hex" value.
109 All remaining parms are considered variable names which are to be
110 sprinted.
111 """
112
113 if len(args) == 0:
114 return
115
116 # Create list from args (which is a tuple) so that it can be modified.
117 args_list = list(args)
118
119 # See if parm 1 is to be interpreted as "indent".
120 try:
121 if type(int(args_list[0])) is int:
122 indent = int(args_list[0])
123 args_list.pop(0)
124 except ValueError:
125 indent = 0
126
127 # See if parm 2 is to be interpreted as "col1_width".
128 try:
129 if type(int(args_list[0])) is int:
130 loc_col1_width = int(args_list[0])
131 args_list.pop(0)
132 except ValueError:
133 loc_col1_width = gp.col1_width
134
135 # See if parm 2 is to be interpreted as "hex".
136 try:
137 if type(int(args_list[0])) is int:
138 hex = int(args_list[0])
139 args_list.pop(0)
140 except ValueError:
141 hex = 0
142
143 buffer = ""
144 for var_name in args_list:
145 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
146 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
147 loc_col1_width)
148
149 return buffer
150
151###############################################################################
152
153
154###############################################################################
155def sprint_pgm_header(indent=0):
156
157 r"""
158 Sprint a standardized header that robot programs should print at the
159 beginning of the run. The header includes useful information like command
160 line, pid, userid, program parameters, etc. Callers need to have declared
161 a global @{parm_list} variable which contains the names of all program
162 parameters.
163 """
164
165 loc_col1_width = gp.col1_width + indent
166
167 linefeed = 0
168 rprintn()
169 suite_name = BuiltIn().get_variable_value("${suite_name}")
170
171 buffer = "\n"
172 buffer += gp.sindent(gp.sprint_time("Running test suite \"" +
173 suite_name + "\".\n"),
174 indent)
175 buffer += gp.sprint_pgm_header(indent, linefeed)
176
177 # Get value of global parm_list.
178 parm_list = BuiltIn().get_variable_value("${parm_list}")
179
180 buffer += sprint_vars(str(indent), str(loc_col1_width), *parm_list)
181 buffer += "\n"
182
183 return buffer
184
185###############################################################################
186
187
188###############################################################################
189def sprint_error_report(error_text="\n"):
190
191 r"""
192 Print a standardized error report that robot programs should print on
193 failure. The report includes useful information like error text, command
194 line, pid, userid, program parameters, etc. Callers must have declared a
195 @{parm_list} variable which contains the names of all program parameters.
196 """
197
198 buffer = ""
199 buffer += gp.sprint_dashes(width=120, char="=")
200 buffer += gp.sprint_error(error_text)
201
202 indent = 2
203 linefeed = 0
204
205 buffer += sprint_pgm_header(indent)
206
207 buffer += gp.sprint_dashes(width=120, char="=")
208
209 return buffer
210
211###############################################################################
212
213
214###############################################################################
215def sprint_issuing_keyword(cmd_buf,
216 test_mode=0):
217
218 r"""
219 Return a line indicating a robot command (i.e. keyword + args) that the
220 program is about to execute.
221
222 For example, for the following robot code...
223
224 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
225 rdprint_issuing_keyword
226
227 The output would look something like this:
228
229 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
230
231 Description of args:
232 cmd_buf A list containing the keyword and
233 arguments to be run.
234 """
235
236 buffer = ""
237 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
238 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
239
240 return buffer
241
242###############################################################################
243
244
245###############################################################################
246def sprint_auto_vars(headers=0):
247
248 r"""
249 This keyword will string print all of the Automatic Variables described in
250 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500251
252 NOTE: Not all automatic variables are guaranteed to exist.
253
254 Description of arguments:
255 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600256 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500257 """
258
Michael Walsh18176322016-11-15 15:11:21 -0600259 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500260 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600261 buffer += gp.sprint_dashes()
262 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500263
Michael Walsh18176322016-11-15 15:11:21 -0600264 buffer += \
265 sprint_vars(
266 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
267 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
268 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
269 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
270 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
271 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
272 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500273
274 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600275 buffer += gp.sprint_dashes()
276
277 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500278
279###############################################################################
280
281
282###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600283# In the following section of code, we will dynamically create robot versions
284# of print functions for each of the sprint functions defined in the
285# gen_print.py module. So, for example, where we have an sprint_time()
286# function defined above that returns the time to the caller in a string, we
287# will create a corresponding rprint_time() function that will print that
288# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500289
Michael Walsh18176322016-11-15 15:11:21 -0600290# It can be complicated to follow what's being created by the exec statement
291# below. Here is an example of the rprint_time() function that will be
292# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500293
Michael Walsh18176322016-11-15 15:11:21 -0600294# def rprint_time(*args):
295# s_func = getattr(gp, "sprint_time")
296# BuiltIn().log_to_console(s_func(*args),
297# stream='STDIN',
298# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500299
Michael Walsh18176322016-11-15 15:11:21 -0600300# Here are comments describing the lines in the body of the created function.
301# Put a reference to the "s" version of this function in s_func.
302# Call the "s" version of this function passing it all of our arguments. Log
303# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500304
Michael Walsh18176322016-11-15 15:11:21 -0600305robot_prefix = "r"
306robot_func_names =\
307 [
308 'print_error_report', 'print_pgm_header',
309 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
310 ]
311func_names = gp.func_names + robot_func_names
312for func_name in func_names:
313 # The print_var function's job is to figure out the name of arg 1 and
314 # then call print_varx. This is not currently supported for robot
315 # programs. Though it IS supported for python modules.
316 if func_name == "print_error" or func_name == "print_error_report":
317 output_stream = "STDERR"
318 else:
319 output_stream = "STDIN"
320 if func_name in robot_func_names:
321 object_name = "__import__(__name__)"
322 else:
323 object_name = "gp"
324 func_def = \
325 [
326 "def " + robot_prefix + func_name + "(*args):",
327 " s_func = getattr(" + object_name + ", \"s" + func_name + "\")",
328 " BuiltIn().log_to_console(s_func(*args),"
329 " stream='" + output_stream + "',"
330 " no_newline=True)"
331 ]
Michael Walshde791732016-09-06 14:25:24 -0500332
Michael Walsh18176322016-11-15 15:11:21 -0600333 pgm_definition_string = '\n'.join(func_def)
334 if gen_robot_print_debug:
335 rprintn(pgm_definition_string)
336 exec(pgm_definition_string)
337
338 # Now define "q" versions of each print function. The q functions only
339 # print if global robot var "quiet" is 0. If the global var quiet is not
340 # defined, it will be treated as though it were "1", i.e. no printing will
341 # be done.
342 func_def = \
343 [
344 "def rq" + func_name + "(*args):",
345 " try:",
346 " quiet = int(BuiltIn().get_variable_value(\"${quiet}\"))",
347 " except TypeError:",
348 " quiet = 1",
349 " if quiet:",
350 " return",
351 " r" + func_name + "(*args)"
352 ]
353
354 pgm_definition_string = '\n'.join(func_def)
355 if gen_robot_print_debug:
356 rprintn(pgm_definition_string)
357 exec(pgm_definition_string)
358
359 # Now define "d" versions of each print function. The d functions only
360 # print if global robot var "debug" is 1.
361 func_def = \
362 [
363 "def rd" + func_name + "(*args):",
364 " try:",
365 " debug = int(BuiltIn().get_variable_value(\"${debug}\"))",
366 " except TypeError:",
367 " debug = 0",
368 " if not debug:",
369 " return",
370 " r" + func_name + "(*args)"
371 ]
372
373 pgm_definition_string = '\n'.join(func_def)
374 if gen_robot_print_debug:
375 rprintn(pgm_definition_string)
376 exec(pgm_definition_string)
377
378 # Create abbreviated aliases (e.g. rpvarx is an alias for rprint_varx).
379 alias = re.sub("print_", "p", func_name)
380 cmd_buf = robot_prefix + alias + " = " + robot_prefix + func_name
381 if gen_robot_print_debug:
382 rprintn(cmd_buf)
383 exec(cmd_buf)
384
385# Define an alias. rpvar is just a special case of rpvars where the args
386# list contains only one element.
387cmd_buf = "rpvar = rpvars"
388if gen_robot_print_debug:
389 rprintn(cmd_buf)
390exec(cmd_buf)
Michael Walshde791732016-09-06 14:25:24 -0500391
392###############################################################################