blob: ded293b8c0665747fdef26a6c043316ce3a3c029 [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 Walsh0fa47622017-02-20 16:11:34 -060030def get_quiet_default(var_value,
31 default=0):
32
33 r"""
34 If var_value is not None, return it. Otherwise, return the global
35 variable of the same name, if it exists. If not, return default.
36
37 This is meant for use by functions needing help assigning dynamic default
38 values to their parameters. Example:
39
40 def func1(parm1=None):
41
42 parm1 = global_default(parm1, 0)
43
44 Description of arguments:
45 var_value The value being evaluated.
46 default The value to be returned if var_value is
47 None AND the global
48 variable of the same name does not exist.
49 """
50
51 var_name = gp.get_arg_name(0, 1, stack_frame_ix=2)
52
53 return dft(var_value, get_mod_global(var_name, 0))
54
55###############################################################################
56
57
58###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -060059def set_quiet_default(quiet=None,
60 default=0):
Michael Walshde791732016-09-06 14:25:24 -050061
Michael Walsh18176322016-11-15 15:11:21 -060062 r"""
63 Return a default value for the quiet variable based on its current value,
64 the value of global ${QUIET} and default.
Michael Walshde791732016-09-06 14:25:24 -050065
Michael Walsh18176322016-11-15 15:11:21 -060066 Description of Arguments:
67 quiet If this is set already, no default value
68 is chosen. Otherwise, it will be set to
69 either the global ${QUIET} robot variable
70 or to default (below).
71 default The default value to be used if global
72 ${QUIET} does not exist.
73 """
Michael Walshde791732016-09-06 14:25:24 -050074
Michael Walsh18176322016-11-15 15:11:21 -060075 if quiet is None:
76 # Set default quiet value.
77 try:
78 quiet = int(BuiltIn().get_variable_value("${quiet}"))
79 except TypeError:
80 quiet = int(default)
81 quiet = int(quiet)
Michael Walshde791732016-09-06 14:25:24 -050082
Michael Walsh18176322016-11-15 15:11:21 -060083 return quiet
Michael Walshde791732016-09-06 14:25:24 -050084
85###############################################################################
86
87
88###############################################################################
Michael Walshafa7a1b2016-12-09 14:02:48 -060089def get_quiet(default=1):
90
91 r"""
92 Get the value of robot variable "quiet" and return it. If "quiet" is not
93 defined, the "default" value is returned.
94
95 Description of arguments:
96 default The value that is returned if robot
97 variable "quiet" is not defined.
98 """
99
100 try:
101 quiet = int(BuiltIn().get_variable_value("${quiet}"))
102 except TypeError:
103 quiet = default
104
105 return quiet
106
107###############################################################################
108
109
110###############################################################################
111def get_debug(default=0):
112
113 r"""
114 Get the value of robot variable "debug" and return it. If "debug" is not
115 defined, the "default" value is returned.
116
117 Description of arguments:
118 default The value that is returned if robot
119 variable "debug" is not defined.
120 """
121
122 try:
123 debug = int(BuiltIn().get_variable_value("${debug}"))
124 except TypeError:
125 debug = default
126
127 return debug
128
129###############################################################################
130
131
132###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500133def rprint(buffer="",
134 stream="STDOUT"):
Michael Walshde791732016-09-06 14:25:24 -0500135
136 r"""
137 rprint stands for "Robot Print". This keyword will print the user's
138 buffer to the console. This keyword does not write a linefeed. It is the
139 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -0600140 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -0500141
142 Description of arguments:
143 buffer The value that is to written to stdout.
144 """
145
Michael Walsh82acf002017-05-04 14:33:05 -0500146 BuiltIn().log_to_console(gp.replace_passwords(str(buffer)),
147 no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -0500148
149###############################################################################
150
151
152###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500153def rprintn(buffer="",
154 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -0500155
156 r"""
157 rprintn stands for "Robot print with linefeed". This keyword will print
158 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -0500159 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -0500160
161 Description of arguments:
162 buffer The value that is to written to stdout.
163 """
164
Michael Walsh82acf002017-05-04 14:33:05 -0500165 BuiltIn().log_to_console(gp.replace_passwords(buffer), no_newline=False,
166 stream=stream)
Michael Walshde791732016-09-06 14:25:24 -0500167
168###############################################################################
169
170
171###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600172def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -0500173
174 r"""
Michael Walsh18176322016-11-15 15:11:21 -0600175 sprint_vars stands for "String Print Vars". This is a robot redefinition
176 of the sprint_vars function in gen_print.py. Given a list of variable
177 names, this keyword will string print each variable name and value such
178 that the value lines up in the same column as messages printed with rptime.
179
180 Description of arguments:
181 args:
182 If the first argument is an integer, it will be interpreted to be the
Michael Walsh18176322016-11-15 15:11:21 -0600183 "hex" value.
Michael Walshc4da0cb2017-01-10 11:31:05 -0600184 If the second argument is an integer, it will be interpreted to be the
185 "indent" value.
186 If the third argument is an integer, it will be interpreted to be the
187 "col1_width" value.
Michael Walsh18176322016-11-15 15:11:21 -0600188 All remaining parms are considered variable names which are to be
189 sprinted.
190 """
191
192 if len(args) == 0:
193 return
194
195 # Create list from args (which is a tuple) so that it can be modified.
196 args_list = list(args)
197
Michael Walshc4da0cb2017-01-10 11:31:05 -0600198 # See if parm 1 is to be interpreted as "hex".
199 try:
200 if type(int(args_list[0])) is int:
201 hex = int(args_list[0])
202 args_list.pop(0)
203 except ValueError:
204 hex = 0
205
206 # See if parm 2 is to be interpreted as "indent".
Michael Walsh18176322016-11-15 15:11:21 -0600207 try:
208 if type(int(args_list[0])) is int:
209 indent = int(args_list[0])
210 args_list.pop(0)
211 except ValueError:
212 indent = 0
213
Michael Walshc4da0cb2017-01-10 11:31:05 -0600214 # See if parm 3 is to be interpreted as "col1_width".
Michael Walsh18176322016-11-15 15:11:21 -0600215 try:
216 if type(int(args_list[0])) is int:
217 loc_col1_width = int(args_list[0])
218 args_list.pop(0)
219 except ValueError:
220 loc_col1_width = gp.col1_width
221
Michael Walsh18176322016-11-15 15:11:21 -0600222 buffer = ""
223 for var_name in args_list:
Michael Walsh0fa47622017-02-20 16:11:34 -0600224 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}")
Michael Walsh18176322016-11-15 15:11:21 -0600225 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
226 loc_col1_width)
227
228 return buffer
229
230###############################################################################
231
232
233###############################################################################
234def sprint_pgm_header(indent=0):
235
236 r"""
237 Sprint a standardized header that robot programs should print at the
238 beginning of the run. The header includes useful information like command
239 line, pid, userid, program parameters, etc. Callers need to have declared
240 a global @{parm_list} variable which contains the names of all program
241 parameters.
242 """
243
244 loc_col1_width = gp.col1_width + indent
245
246 linefeed = 0
247 rprintn()
248 suite_name = BuiltIn().get_variable_value("${suite_name}")
249
250 buffer = "\n"
251 buffer += gp.sindent(gp.sprint_time("Running test suite \"" +
252 suite_name + "\".\n"),
253 indent)
254 buffer += gp.sprint_pgm_header(indent, linefeed)
255
256 # Get value of global parm_list.
257 parm_list = BuiltIn().get_variable_value("${parm_list}")
258
Michael Walshc4da0cb2017-01-10 11:31:05 -0600259 buffer += sprint_vars(0, str(indent), str(loc_col1_width), *parm_list)
Michael Walsh18176322016-11-15 15:11:21 -0600260 buffer += "\n"
261
Michael Walsha6723f22016-11-22 11:12:01 -0600262 # Setting global program_pid.
263 BuiltIn().set_global_variable("${program_pid}", os.getpid())
264
Michael Walsh18176322016-11-15 15:11:21 -0600265 return buffer
266
267###############################################################################
268
269
270###############################################################################
271def sprint_error_report(error_text="\n"):
272
273 r"""
274 Print a standardized error report that robot programs should print on
275 failure. The report includes useful information like error text, command
276 line, pid, userid, program parameters, etc. Callers must have declared a
277 @{parm_list} variable which contains the names of all program parameters.
278 """
279
Michael Walshafa7a1b2016-12-09 14:02:48 -0600280 try:
281 error_report_format = int(BuiltIn().get_variable_value(
282 "${error_report_format}"))
283 except TypeError:
284 error_report_format = 0
285
286 # Currently, supported values for error_report_format are:
287 # 0 - Short form
288 # 1 - Long form
289
290 error_text = error_text.rstrip('\n') + '\n'
291
292 if error_report_format == 0:
293 return gp.sprint_error(error_text)
294
Michael Walsh18176322016-11-15 15:11:21 -0600295 buffer = ""
296 buffer += gp.sprint_dashes(width=120, char="=")
297 buffer += gp.sprint_error(error_text)
298
299 indent = 2
300 linefeed = 0
301
302 buffer += sprint_pgm_header(indent)
303
304 buffer += gp.sprint_dashes(width=120, char="=")
305
306 return buffer
307
308###############################################################################
309
310
311###############################################################################
312def sprint_issuing_keyword(cmd_buf,
313 test_mode=0):
314
315 r"""
316 Return a line indicating a robot command (i.e. keyword + args) that the
317 program is about to execute.
318
319 For example, for the following robot code...
320
321 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
322 rdprint_issuing_keyword
323
324 The output would look something like this:
325
326 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
327
328 Description of args:
329 cmd_buf A list containing the keyword and
330 arguments to be run.
331 """
332
333 buffer = ""
334 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
335 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
336
337 return buffer
338
339###############################################################################
340
341
342###############################################################################
343def sprint_auto_vars(headers=0):
344
345 r"""
346 This keyword will string print all of the Automatic Variables described in
347 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500348
349 NOTE: Not all automatic variables are guaranteed to exist.
350
351 Description of arguments:
352 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600353 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500354 """
355
Michael Walsh18176322016-11-15 15:11:21 -0600356 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500357 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600358 buffer += gp.sprint_dashes()
359 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500360
Michael Walsh18176322016-11-15 15:11:21 -0600361 buffer += \
362 sprint_vars(
363 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
364 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
365 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
366 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
367 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
368 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
369 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500370
371 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600372 buffer += gp.sprint_dashes()
373
374 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500375
376###############################################################################
377
378
379###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600380# In the following section of code, we will dynamically create robot versions
381# of print functions for each of the sprint functions defined in the
382# gen_print.py module. So, for example, where we have an sprint_time()
383# function defined above that returns the time to the caller in a string, we
384# will create a corresponding rprint_time() function that will print that
385# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500386
Michael Walsh18176322016-11-15 15:11:21 -0600387# It can be complicated to follow what's being created by the exec statement
388# below. Here is an example of the rprint_time() function that will be
389# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500390
Michael Walsh18176322016-11-15 15:11:21 -0600391# def rprint_time(*args):
392# s_func = getattr(gp, "sprint_time")
393# BuiltIn().log_to_console(s_func(*args),
394# stream='STDIN',
395# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500396
Michael Walsh18176322016-11-15 15:11:21 -0600397# Here are comments describing the lines in the body of the created function.
398# Put a reference to the "s" version of this function in s_func.
399# Call the "s" version of this function passing it all of our arguments. Log
400# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500401
Michael Walsh18176322016-11-15 15:11:21 -0600402robot_prefix = "r"
403robot_func_names =\
404 [
405 'print_error_report', 'print_pgm_header',
406 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
407 ]
408func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600409
Michael Walshafa7a1b2016-12-09 14:02:48 -0600410explicit_definitions = ['print', 'printn']
411
Michael Walsha6723f22016-11-22 11:12:01 -0600412func_names = list(my_ord_dict.fromkeys(func_names))
413
414if gen_robot_print_debug:
415 rprintn()
416 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
417 rprintn()
418
Michael Walsh18176322016-11-15 15:11:21 -0600419for func_name in func_names:
Michael Walshde791732016-09-06 14:25:24 -0500420
Michael Walshafa7a1b2016-12-09 14:02:48 -0600421 if func_name not in explicit_definitions:
422 # The print_var function's job is to figure out the name of arg 1 and
423 # then call print_varx. This is not currently supported for robot
424 # programs. Though it IS supported for python modules.
425 if func_name == "print_error" or func_name == "print_error_report":
426 output_stream = "STDERR"
427 else:
428 output_stream = "STDIN"
429 if func_name in robot_func_names:
430 object_name = "__import__(__name__)"
431 else:
432 object_name = "gp"
433 func_def = \
434 [
435 "def " + robot_prefix + func_name + "(*args):",
436 " s_func = getattr(" + object_name + ", \"s" + func_name +
437 "\")",
Michael Walsh82acf002017-05-04 14:33:05 -0500438 " BuiltIn().log_to_console" +
439 "(gp.replace_passwords(s_func(*args)),"
Michael Walshafa7a1b2016-12-09 14:02:48 -0600440 " stream='" + output_stream + "',"
441 " no_newline=True)"
442 ]
443
444 pgm_definition_string = '\n'.join(func_def)
445 if gen_robot_print_debug:
446 rprintn()
447 rprintn(pgm_definition_string)
448 exec(pgm_definition_string)
Michael Walsh18176322016-11-15 15:11:21 -0600449
450 # Now define "q" versions of each print function. The q functions only
451 # print if global robot var "quiet" is 0. If the global var quiet is not
452 # defined, it will be treated as though it were "1", i.e. no printing will
453 # be done.
454 func_def = \
455 [
456 "def rq" + func_name + "(*args):",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600457 " if get_quiet():",
458 " return",
459 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600460 ]
461
462 pgm_definition_string = '\n'.join(func_def)
463 if gen_robot_print_debug:
464 rprintn(pgm_definition_string)
465 exec(pgm_definition_string)
466
467 # Now define "d" versions of each print function. The d functions only
468 # print if global robot var "debug" is 1.
469 func_def = \
470 [
471 "def rd" + func_name + "(*args):",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600472 " if not get_debug():",
473 " return",
474 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600475 ]
476
477 pgm_definition_string = '\n'.join(func_def)
478 if gen_robot_print_debug:
479 rprintn(pgm_definition_string)
480 exec(pgm_definition_string)
481
Michael Walshafa7a1b2016-12-09 14:02:48 -0600482 # Create shorter aliases.
Michael Walsha6723f22016-11-22 11:12:01 -0600483 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600484 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600485 for prefix2 in prefixes:
486 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
487 prefix2 + func_name
488 if gen_robot_print_debug:
489 rprintn(cmd_buf)
490 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600491
492# Define an alias. rpvar is just a special case of rpvars where the args
493# list contains only one element.
494cmd_buf = "rpvar = rpvars"
495if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600496 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600497 rprintn(cmd_buf)
498exec(cmd_buf)
Michael Walshde791732016-09-06 14:25:24 -0500499
500###############################################################################