blob: 7c4891262f9ff67cc31f0b2b3c054920ad86b1be [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
21
Michael Walsh18176322016-11-15 15:11:21 -060022try:
23 # The user can set environment variable "GEN_ROBOT_PRINT_DEBUG" to get
24 # debug output from this module.
Michael Walsha6723f22016-11-22 11:12:01 -060025 gen_robot_print_debug = int(os.environ['GEN_ROBOT_PRINT_DEBUG'])
Michael Walsh18176322016-11-15 15:11:21 -060026except KeyError:
27 gen_robot_print_debug = 0
28
29
Michael Walshde791732016-09-06 14:25:24 -050030###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -060031def set_quiet_default(quiet=None,
32 default=0):
Michael Walshde791732016-09-06 14:25:24 -050033
Michael Walsh18176322016-11-15 15:11:21 -060034 r"""
35 Return a default value for the quiet variable based on its current value,
36 the value of global ${QUIET} and default.
Michael Walshde791732016-09-06 14:25:24 -050037
Michael Walsh18176322016-11-15 15:11:21 -060038 Description of Arguments:
39 quiet If this is set already, no default value
40 is chosen. Otherwise, it will be set to
41 either the global ${QUIET} robot variable
42 or to default (below).
43 default The default value to be used if global
44 ${QUIET} does not exist.
45 """
Michael Walshde791732016-09-06 14:25:24 -050046
Michael Walsh18176322016-11-15 15:11:21 -060047 if quiet is None:
48 # Set default quiet value.
49 try:
50 quiet = int(BuiltIn().get_variable_value("${quiet}"))
51 except TypeError:
52 quiet = int(default)
53 quiet = int(quiet)
Michael Walshde791732016-09-06 14:25:24 -050054
Michael Walsh18176322016-11-15 15:11:21 -060055 return quiet
Michael Walshde791732016-09-06 14:25:24 -050056
57###############################################################################
58
59
60###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -050061def rprint(buffer="",
62 stream="STDOUT"):
Michael Walshde791732016-09-06 14:25:24 -050063
64 r"""
65 rprint stands for "Robot Print". This keyword will print the user's
66 buffer to the console. This keyword does not write a linefeed. It is the
67 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -060068 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -050069
70 Description of arguments:
71 buffer The value that is to written to stdout.
72 """
73
Michael Walsh18176322016-11-15 15:11:21 -060074 BuiltIn().log_to_console(str(buffer), no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050075
76###############################################################################
77
78
79###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -050080def rprintn(buffer="",
81 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -050082
83 r"""
84 rprintn stands for "Robot print with linefeed". This keyword will print
85 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -050086 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -050087
88 Description of arguments:
89 buffer The value that is to written to stdout.
90 """
91
Michael Walsh7423c012016-10-04 10:27:21 -050092 BuiltIn().log_to_console(buffer, no_newline=False, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -050093
94###############################################################################
95
96
97###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -060098def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -050099
100 r"""
Michael Walsh18176322016-11-15 15:11:21 -0600101 sprint_vars stands for "String Print Vars". This is a robot redefinition
102 of the sprint_vars function in gen_print.py. Given a list of variable
103 names, this keyword will string print each variable name and value such
104 that the value lines up in the same column as messages printed with rptime.
105
106 Description of arguments:
107 args:
108 If the first argument is an integer, it will be interpreted to be the
109 "indent" value.
110 If the second argument is an integer, it will be interpreted to be the
111 "col1_width" value.
112 If the third argument is an integer, it will be interpreted to be the
113 "hex" value.
114 All remaining parms are considered variable names which are to be
115 sprinted.
116 """
117
118 if len(args) == 0:
119 return
120
121 # Create list from args (which is a tuple) so that it can be modified.
122 args_list = list(args)
123
124 # See if parm 1 is to be interpreted as "indent".
125 try:
126 if type(int(args_list[0])) is int:
127 indent = int(args_list[0])
128 args_list.pop(0)
129 except ValueError:
130 indent = 0
131
132 # See if parm 2 is to be interpreted as "col1_width".
133 try:
134 if type(int(args_list[0])) is int:
135 loc_col1_width = int(args_list[0])
136 args_list.pop(0)
137 except ValueError:
138 loc_col1_width = gp.col1_width
139
140 # See if parm 2 is to be interpreted as "hex".
141 try:
142 if type(int(args_list[0])) is int:
143 hex = int(args_list[0])
144 args_list.pop(0)
145 except ValueError:
146 hex = 0
147
148 buffer = ""
149 for var_name in args_list:
150 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
151 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
152 loc_col1_width)
153
154 return buffer
155
156###############################################################################
157
158
159###############################################################################
160def sprint_pgm_header(indent=0):
161
162 r"""
163 Sprint a standardized header that robot programs should print at the
164 beginning of the run. The header includes useful information like command
165 line, pid, userid, program parameters, etc. Callers need to have declared
166 a global @{parm_list} variable which contains the names of all program
167 parameters.
168 """
169
170 loc_col1_width = gp.col1_width + indent
171
172 linefeed = 0
173 rprintn()
174 suite_name = BuiltIn().get_variable_value("${suite_name}")
175
176 buffer = "\n"
177 buffer += gp.sindent(gp.sprint_time("Running test suite \"" +
178 suite_name + "\".\n"),
179 indent)
180 buffer += gp.sprint_pgm_header(indent, linefeed)
181
182 # Get value of global parm_list.
183 parm_list = BuiltIn().get_variable_value("${parm_list}")
184
185 buffer += sprint_vars(str(indent), str(loc_col1_width), *parm_list)
186 buffer += "\n"
187
Michael Walsha6723f22016-11-22 11:12:01 -0600188 # Setting global program_pid.
189 BuiltIn().set_global_variable("${program_pid}", os.getpid())
190
Michael Walsh18176322016-11-15 15:11:21 -0600191 return buffer
192
193###############################################################################
194
195
196###############################################################################
197def sprint_error_report(error_text="\n"):
198
199 r"""
200 Print a standardized error report that robot programs should print on
201 failure. The report includes useful information like error text, command
202 line, pid, userid, program parameters, etc. Callers must have declared a
203 @{parm_list} variable which contains the names of all program parameters.
204 """
205
206 buffer = ""
207 buffer += gp.sprint_dashes(width=120, char="=")
208 buffer += gp.sprint_error(error_text)
209
210 indent = 2
211 linefeed = 0
212
213 buffer += sprint_pgm_header(indent)
214
215 buffer += gp.sprint_dashes(width=120, char="=")
216
217 return buffer
218
219###############################################################################
220
221
222###############################################################################
223def sprint_issuing_keyword(cmd_buf,
224 test_mode=0):
225
226 r"""
227 Return a line indicating a robot command (i.e. keyword + args) that the
228 program is about to execute.
229
230 For example, for the following robot code...
231
232 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
233 rdprint_issuing_keyword
234
235 The output would look something like this:
236
237 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
238
239 Description of args:
240 cmd_buf A list containing the keyword and
241 arguments to be run.
242 """
243
244 buffer = ""
245 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
246 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
247
248 return buffer
249
250###############################################################################
251
252
253###############################################################################
254def sprint_auto_vars(headers=0):
255
256 r"""
257 This keyword will string print all of the Automatic Variables described in
258 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500259
260 NOTE: Not all automatic variables are guaranteed to exist.
261
262 Description of arguments:
263 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600264 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500265 """
266
Michael Walsh18176322016-11-15 15:11:21 -0600267 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500268 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600269 buffer += gp.sprint_dashes()
270 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500271
Michael Walsh18176322016-11-15 15:11:21 -0600272 buffer += \
273 sprint_vars(
274 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
275 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
276 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
277 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
278 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
279 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
280 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500281
282 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600283 buffer += gp.sprint_dashes()
284
285 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500286
287###############################################################################
288
289
290###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600291# In the following section of code, we will dynamically create robot versions
292# of print functions for each of the sprint functions defined in the
293# gen_print.py module. So, for example, where we have an sprint_time()
294# function defined above that returns the time to the caller in a string, we
295# will create a corresponding rprint_time() function that will print that
296# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500297
Michael Walsh18176322016-11-15 15:11:21 -0600298# It can be complicated to follow what's being created by the exec statement
299# below. Here is an example of the rprint_time() function that will be
300# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500301
Michael Walsh18176322016-11-15 15:11:21 -0600302# def rprint_time(*args):
303# s_func = getattr(gp, "sprint_time")
304# BuiltIn().log_to_console(s_func(*args),
305# stream='STDIN',
306# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500307
Michael Walsh18176322016-11-15 15:11:21 -0600308# Here are comments describing the lines in the body of the created function.
309# Put a reference to the "s" version of this function in s_func.
310# Call the "s" version of this function passing it all of our arguments. Log
311# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500312
Michael Walsh18176322016-11-15 15:11:21 -0600313robot_prefix = "r"
314robot_func_names =\
315 [
316 'print_error_report', 'print_pgm_header',
317 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
318 ]
319func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600320
321func_names = list(my_ord_dict.fromkeys(func_names))
322
323if gen_robot_print_debug:
324 rprintn()
325 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
326 rprintn()
327
Michael Walsh18176322016-11-15 15:11:21 -0600328for func_name in func_names:
329 # The print_var function's job is to figure out the name of arg 1 and
330 # then call print_varx. This is not currently supported for robot
331 # programs. Though it IS supported for python modules.
332 if func_name == "print_error" or func_name == "print_error_report":
333 output_stream = "STDERR"
334 else:
335 output_stream = "STDIN"
336 if func_name in robot_func_names:
337 object_name = "__import__(__name__)"
338 else:
339 object_name = "gp"
340 func_def = \
341 [
342 "def " + robot_prefix + func_name + "(*args):",
343 " s_func = getattr(" + object_name + ", \"s" + func_name + "\")",
344 " BuiltIn().log_to_console(s_func(*args),"
345 " stream='" + output_stream + "',"
346 " no_newline=True)"
347 ]
Michael Walshde791732016-09-06 14:25:24 -0500348
Michael Walsh18176322016-11-15 15:11:21 -0600349 pgm_definition_string = '\n'.join(func_def)
350 if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600351 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600352 rprintn(pgm_definition_string)
353 exec(pgm_definition_string)
354
355 # Now define "q" versions of each print function. The q functions only
356 # print if global robot var "quiet" is 0. If the global var quiet is not
357 # defined, it will be treated as though it were "1", i.e. no printing will
358 # be done.
359 func_def = \
360 [
361 "def rq" + func_name + "(*args):",
362 " try:",
363 " quiet = int(BuiltIn().get_variable_value(\"${quiet}\"))",
364 " except TypeError:",
365 " quiet = 1",
366 " if quiet:",
367 " return",
368 " r" + func_name + "(*args)"
369 ]
370
371 pgm_definition_string = '\n'.join(func_def)
372 if gen_robot_print_debug:
373 rprintn(pgm_definition_string)
374 exec(pgm_definition_string)
375
376 # Now define "d" versions of each print function. The d functions only
377 # print if global robot var "debug" is 1.
378 func_def = \
379 [
380 "def rd" + func_name + "(*args):",
381 " try:",
382 " debug = int(BuiltIn().get_variable_value(\"${debug}\"))",
383 " except TypeError:",
384 " debug = 0",
385 " if not debug:",
386 " return",
387 " r" + func_name + "(*args)"
388 ]
389
390 pgm_definition_string = '\n'.join(func_def)
391 if gen_robot_print_debug:
392 rprintn(pgm_definition_string)
393 exec(pgm_definition_string)
394
Michael Walsha6723f22016-11-22 11:12:01 -0600395 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600396 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600397 for prefix2 in prefixes:
398 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
399 prefix2 + func_name
400 if gen_robot_print_debug:
401 rprintn(cmd_buf)
402 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600403
404# Define an alias. rpvar is just a special case of rpvars where the args
405# list contains only one element.
406cmd_buf = "rpvar = rpvars"
407if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600408 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600409 rprintn(cmd_buf)
410exec(cmd_buf)
Michael Walshde791732016-09-06 14:25:24 -0500411
412###############################################################################