blob: 6d4d57042c41156942a6797e6ea38b92b1a30e24 [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 Walsh18176322016-11-15 15:11:21 -0600146 BuiltIn().log_to_console(str(buffer), no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -0500147
148###############################################################################
149
150
151###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500152def rprintn(buffer="",
153 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -0500154
155 r"""
156 rprintn stands for "Robot print with linefeed". This keyword will print
157 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -0500158 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -0500159
160 Description of arguments:
161 buffer The value that is to written to stdout.
162 """
163
Michael Walsh7423c012016-10-04 10:27:21 -0500164 BuiltIn().log_to_console(buffer, no_newline=False, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -0500165
166###############################################################################
167
168
169###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600170def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -0500171
172 r"""
Michael Walsh18176322016-11-15 15:11:21 -0600173 sprint_vars stands for "String Print Vars". This is a robot redefinition
174 of the sprint_vars function in gen_print.py. Given a list of variable
175 names, this keyword will string print each variable name and value such
176 that the value lines up in the same column as messages printed with rptime.
177
178 Description of arguments:
179 args:
180 If the first argument is an integer, it will be interpreted to be the
Michael Walsh18176322016-11-15 15:11:21 -0600181 "hex" value.
Michael Walshc4da0cb2017-01-10 11:31:05 -0600182 If the second argument is an integer, it will be interpreted to be the
183 "indent" value.
184 If the third argument is an integer, it will be interpreted to be the
185 "col1_width" value.
Michael Walsh18176322016-11-15 15:11:21 -0600186 All remaining parms are considered variable names which are to be
187 sprinted.
188 """
189
190 if len(args) == 0:
191 return
192
193 # Create list from args (which is a tuple) so that it can be modified.
194 args_list = list(args)
195
Michael Walshc4da0cb2017-01-10 11:31:05 -0600196 # See if parm 1 is to be interpreted as "hex".
197 try:
198 if type(int(args_list[0])) is int:
199 hex = int(args_list[0])
200 args_list.pop(0)
201 except ValueError:
202 hex = 0
203
204 # See if parm 2 is to be interpreted as "indent".
Michael Walsh18176322016-11-15 15:11:21 -0600205 try:
206 if type(int(args_list[0])) is int:
207 indent = int(args_list[0])
208 args_list.pop(0)
209 except ValueError:
210 indent = 0
211
Michael Walshc4da0cb2017-01-10 11:31:05 -0600212 # See if parm 3 is to be interpreted as "col1_width".
Michael Walsh18176322016-11-15 15:11:21 -0600213 try:
214 if type(int(args_list[0])) is int:
215 loc_col1_width = int(args_list[0])
216 args_list.pop(0)
217 except ValueError:
218 loc_col1_width = gp.col1_width
219
Michael Walsh18176322016-11-15 15:11:21 -0600220 buffer = ""
221 for var_name in args_list:
Michael Walsh0fa47622017-02-20 16:11:34 -0600222 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}")
Michael Walsh18176322016-11-15 15:11:21 -0600223 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
224 loc_col1_width)
225
226 return buffer
227
228###############################################################################
229
230
231###############################################################################
232def sprint_pgm_header(indent=0):
233
234 r"""
235 Sprint a standardized header that robot programs should print at the
236 beginning of the run. The header includes useful information like command
237 line, pid, userid, program parameters, etc. Callers need to have declared
238 a global @{parm_list} variable which contains the names of all program
239 parameters.
240 """
241
242 loc_col1_width = gp.col1_width + indent
243
244 linefeed = 0
245 rprintn()
246 suite_name = BuiltIn().get_variable_value("${suite_name}")
247
248 buffer = "\n"
249 buffer += gp.sindent(gp.sprint_time("Running test suite \"" +
250 suite_name + "\".\n"),
251 indent)
252 buffer += gp.sprint_pgm_header(indent, linefeed)
253
254 # Get value of global parm_list.
255 parm_list = BuiltIn().get_variable_value("${parm_list}")
256
Michael Walshc4da0cb2017-01-10 11:31:05 -0600257 buffer += sprint_vars(0, str(indent), str(loc_col1_width), *parm_list)
Michael Walsh18176322016-11-15 15:11:21 -0600258 buffer += "\n"
259
Michael Walsha6723f22016-11-22 11:12:01 -0600260 # Setting global program_pid.
261 BuiltIn().set_global_variable("${program_pid}", os.getpid())
262
Michael Walsh18176322016-11-15 15:11:21 -0600263 return buffer
264
265###############################################################################
266
267
268###############################################################################
269def sprint_error_report(error_text="\n"):
270
271 r"""
272 Print a standardized error report that robot programs should print on
273 failure. The report includes useful information like error text, command
274 line, pid, userid, program parameters, etc. Callers must have declared a
275 @{parm_list} variable which contains the names of all program parameters.
276 """
277
Michael Walshafa7a1b2016-12-09 14:02:48 -0600278 try:
279 error_report_format = int(BuiltIn().get_variable_value(
280 "${error_report_format}"))
281 except TypeError:
282 error_report_format = 0
283
284 # Currently, supported values for error_report_format are:
285 # 0 - Short form
286 # 1 - Long form
287
288 error_text = error_text.rstrip('\n') + '\n'
289
290 if error_report_format == 0:
291 return gp.sprint_error(error_text)
292
Michael Walsh18176322016-11-15 15:11:21 -0600293 buffer = ""
294 buffer += gp.sprint_dashes(width=120, char="=")
295 buffer += gp.sprint_error(error_text)
296
297 indent = 2
298 linefeed = 0
299
300 buffer += sprint_pgm_header(indent)
301
302 buffer += gp.sprint_dashes(width=120, char="=")
303
304 return buffer
305
306###############################################################################
307
308
309###############################################################################
310def sprint_issuing_keyword(cmd_buf,
311 test_mode=0):
312
313 r"""
314 Return a line indicating a robot command (i.e. keyword + args) that the
315 program is about to execute.
316
317 For example, for the following robot code...
318
319 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
320 rdprint_issuing_keyword
321
322 The output would look something like this:
323
324 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
325
326 Description of args:
327 cmd_buf A list containing the keyword and
328 arguments to be run.
329 """
330
331 buffer = ""
332 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
333 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
334
335 return buffer
336
337###############################################################################
338
339
340###############################################################################
341def sprint_auto_vars(headers=0):
342
343 r"""
344 This keyword will string print all of the Automatic Variables described in
345 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500346
347 NOTE: Not all automatic variables are guaranteed to exist.
348
349 Description of arguments:
350 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600351 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500352 """
353
Michael Walsh18176322016-11-15 15:11:21 -0600354 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500355 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600356 buffer += gp.sprint_dashes()
357 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500358
Michael Walsh18176322016-11-15 15:11:21 -0600359 buffer += \
360 sprint_vars(
361 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
362 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
363 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
364 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
365 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
366 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
367 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500368
369 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600370 buffer += gp.sprint_dashes()
371
372 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500373
374###############################################################################
375
376
377###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600378# In the following section of code, we will dynamically create robot versions
379# of print functions for each of the sprint functions defined in the
380# gen_print.py module. So, for example, where we have an sprint_time()
381# function defined above that returns the time to the caller in a string, we
382# will create a corresponding rprint_time() function that will print that
383# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500384
Michael Walsh18176322016-11-15 15:11:21 -0600385# It can be complicated to follow what's being created by the exec statement
386# below. Here is an example of the rprint_time() function that will be
387# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500388
Michael Walsh18176322016-11-15 15:11:21 -0600389# def rprint_time(*args):
390# s_func = getattr(gp, "sprint_time")
391# BuiltIn().log_to_console(s_func(*args),
392# stream='STDIN',
393# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500394
Michael Walsh18176322016-11-15 15:11:21 -0600395# Here are comments describing the lines in the body of the created function.
396# Put a reference to the "s" version of this function in s_func.
397# Call the "s" version of this function passing it all of our arguments. Log
398# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500399
Michael Walsh18176322016-11-15 15:11:21 -0600400robot_prefix = "r"
401robot_func_names =\
402 [
403 'print_error_report', 'print_pgm_header',
404 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
405 ]
406func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600407
Michael Walshafa7a1b2016-12-09 14:02:48 -0600408explicit_definitions = ['print', 'printn']
409
Michael Walsha6723f22016-11-22 11:12:01 -0600410func_names = list(my_ord_dict.fromkeys(func_names))
411
412if gen_robot_print_debug:
413 rprintn()
414 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
415 rprintn()
416
Michael Walsh18176322016-11-15 15:11:21 -0600417for func_name in func_names:
Michael Walshde791732016-09-06 14:25:24 -0500418
Michael Walshafa7a1b2016-12-09 14:02:48 -0600419 if func_name not in explicit_definitions:
420 # The print_var function's job is to figure out the name of arg 1 and
421 # then call print_varx. This is not currently supported for robot
422 # programs. Though it IS supported for python modules.
423 if func_name == "print_error" or func_name == "print_error_report":
424 output_stream = "STDERR"
425 else:
426 output_stream = "STDIN"
427 if func_name in robot_func_names:
428 object_name = "__import__(__name__)"
429 else:
430 object_name = "gp"
431 func_def = \
432 [
433 "def " + robot_prefix + func_name + "(*args):",
434 " s_func = getattr(" + object_name + ", \"s" + func_name +
435 "\")",
436 " BuiltIn().log_to_console(s_func(*args),"
437 " stream='" + output_stream + "',"
438 " no_newline=True)"
439 ]
440
441 pgm_definition_string = '\n'.join(func_def)
442 if gen_robot_print_debug:
443 rprintn()
444 rprintn(pgm_definition_string)
445 exec(pgm_definition_string)
Michael Walsh18176322016-11-15 15:11:21 -0600446
447 # Now define "q" versions of each print function. The q functions only
448 # print if global robot var "quiet" is 0. If the global var quiet is not
449 # defined, it will be treated as though it were "1", i.e. no printing will
450 # be done.
451 func_def = \
452 [
453 "def rq" + func_name + "(*args):",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600454 " if get_quiet():",
455 " return",
456 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600457 ]
458
459 pgm_definition_string = '\n'.join(func_def)
460 if gen_robot_print_debug:
461 rprintn(pgm_definition_string)
462 exec(pgm_definition_string)
463
464 # Now define "d" versions of each print function. The d functions only
465 # print if global robot var "debug" is 1.
466 func_def = \
467 [
468 "def rd" + func_name + "(*args):",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600469 " if not get_debug():",
470 " return",
471 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600472 ]
473
474 pgm_definition_string = '\n'.join(func_def)
475 if gen_robot_print_debug:
476 rprintn(pgm_definition_string)
477 exec(pgm_definition_string)
478
Michael Walshafa7a1b2016-12-09 14:02:48 -0600479 # Create shorter aliases.
Michael Walsha6723f22016-11-22 11:12:01 -0600480 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600481 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600482 for prefix2 in prefixes:
483 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
484 prefix2 + func_name
485 if gen_robot_print_debug:
486 rprintn(cmd_buf)
487 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600488
489# Define an alias. rpvar is just a special case of rpvars where the args
490# list contains only one element.
491cmd_buf = "rpvar = rpvars"
492if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600493 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600494 rprintn(cmd_buf)
495exec(cmd_buf)
Michael Walshde791732016-09-06 14:25:24 -0500496
497###############################################################################