blob: 7e3d058d49512f191f4f7fca70669056d15dcc6b [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 Walsh18176322016-11-15 15:11:21 -060030def set_quiet_default(quiet=None,
31 default=0):
Michael Walshde791732016-09-06 14:25:24 -050032
Michael Walsh18176322016-11-15 15:11:21 -060033 r"""
34 Return a default value for the quiet variable based on its current value,
35 the value of global ${QUIET} and default.
Michael Walshde791732016-09-06 14:25:24 -050036
Michael Walsh18176322016-11-15 15:11:21 -060037 Description of Arguments:
38 quiet If this is set already, no default value
39 is chosen. Otherwise, it will be set to
40 either the global ${QUIET} robot variable
41 or to default (below).
42 default The default value to be used if global
43 ${QUIET} does not exist.
44 """
Michael Walshde791732016-09-06 14:25:24 -050045
Michael Walsh18176322016-11-15 15:11:21 -060046 if quiet is None:
47 # Set default quiet value.
48 try:
49 quiet = int(BuiltIn().get_variable_value("${quiet}"))
50 except TypeError:
51 quiet = int(default)
52 quiet = int(quiet)
Michael Walshde791732016-09-06 14:25:24 -050053
Michael Walsh18176322016-11-15 15:11:21 -060054 return quiet
Michael Walshde791732016-09-06 14:25:24 -050055
56###############################################################################
57
58
59###############################################################################
Michael Walshafa7a1b2016-12-09 14:02:48 -060060def get_quiet(default=1):
61
62 r"""
63 Get the value of robot variable "quiet" and return it. If "quiet" is not
64 defined, the "default" value is returned.
65
66 Description of arguments:
67 default The value that is returned if robot
68 variable "quiet" is not defined.
69 """
70
71 try:
72 quiet = int(BuiltIn().get_variable_value("${quiet}"))
73 except TypeError:
74 quiet = default
75
76 return quiet
77
78###############################################################################
79
80
81###############################################################################
82def get_debug(default=0):
83
84 r"""
85 Get the value of robot variable "debug" and return it. If "debug" is not
86 defined, the "default" value is returned.
87
88 Description of arguments:
89 default The value that is returned if robot
90 variable "debug" is not defined.
91 """
92
93 try:
94 debug = int(BuiltIn().get_variable_value("${debug}"))
95 except TypeError:
96 debug = default
97
98 return debug
99
100###############################################################################
101
102
103###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500104def rprint(buffer="",
105 stream="STDOUT"):
Michael Walshde791732016-09-06 14:25:24 -0500106
107 r"""
108 rprint stands for "Robot Print". This keyword will print the user's
109 buffer to the console. This keyword does not write a linefeed. It is the
110 responsibility of the caller to include a line feed if desired. This
Michael Walsh18176322016-11-15 15:11:21 -0600111 keyword is essentially an alias for "Log to Console <string> <stream>".
Michael Walshde791732016-09-06 14:25:24 -0500112
113 Description of arguments:
114 buffer The value that is to written to stdout.
115 """
116
Michael Walsh18176322016-11-15 15:11:21 -0600117 BuiltIn().log_to_console(str(buffer), no_newline=True, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -0500118
119###############################################################################
120
121
122###############################################################################
Michael Walsh7423c012016-10-04 10:27:21 -0500123def rprintn(buffer="",
124 stream='STDOUT'):
Michael Walshde791732016-09-06 14:25:24 -0500125
126 r"""
127 rprintn stands for "Robot print with linefeed". This keyword will print
128 the user's buffer to the console along with a linefeed. It is basically
Michael Walsh7423c012016-10-04 10:27:21 -0500129 an abbreviated form of "Log go Console <string> <stream>"
Michael Walshde791732016-09-06 14:25:24 -0500130
131 Description of arguments:
132 buffer The value that is to written to stdout.
133 """
134
Michael Walsh7423c012016-10-04 10:27:21 -0500135 BuiltIn().log_to_console(buffer, no_newline=False, stream=stream)
Michael Walshde791732016-09-06 14:25:24 -0500136
137###############################################################################
138
139
140###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600141def sprint_vars(*args):
Michael Walshde791732016-09-06 14:25:24 -0500142
143 r"""
Michael Walsh18176322016-11-15 15:11:21 -0600144 sprint_vars stands for "String Print Vars". This is a robot redefinition
145 of the sprint_vars function in gen_print.py. Given a list of variable
146 names, this keyword will string print each variable name and value such
147 that the value lines up in the same column as messages printed with rptime.
148
149 Description of arguments:
150 args:
151 If the first argument is an integer, it will be interpreted to be the
152 "indent" value.
153 If the second argument is an integer, it will be interpreted to be the
154 "col1_width" value.
155 If the third argument is an integer, it will be interpreted to be the
156 "hex" value.
157 All remaining parms are considered variable names which are to be
158 sprinted.
159 """
160
161 if len(args) == 0:
162 return
163
164 # Create list from args (which is a tuple) so that it can be modified.
165 args_list = list(args)
166
167 # See if parm 1 is to be interpreted as "indent".
168 try:
169 if type(int(args_list[0])) is int:
170 indent = int(args_list[0])
171 args_list.pop(0)
172 except ValueError:
173 indent = 0
174
175 # See if parm 2 is to be interpreted as "col1_width".
176 try:
177 if type(int(args_list[0])) is int:
178 loc_col1_width = int(args_list[0])
179 args_list.pop(0)
180 except ValueError:
181 loc_col1_width = gp.col1_width
182
183 # See if parm 2 is to be interpreted as "hex".
184 try:
185 if type(int(args_list[0])) is int:
186 hex = int(args_list[0])
187 args_list.pop(0)
188 except ValueError:
189 hex = 0
190
191 buffer = ""
192 for var_name in args_list:
193 var_value = BuiltIn().get_variable_value("${" + var_name + "}")
194 buffer += gp.sprint_varx(var_name, var_value, hex, indent,
195 loc_col1_width)
196
197 return buffer
198
199###############################################################################
200
201
202###############################################################################
203def sprint_pgm_header(indent=0):
204
205 r"""
206 Sprint a standardized header that robot programs should print at the
207 beginning of the run. The header includes useful information like command
208 line, pid, userid, program parameters, etc. Callers need to have declared
209 a global @{parm_list} variable which contains the names of all program
210 parameters.
211 """
212
213 loc_col1_width = gp.col1_width + indent
214
215 linefeed = 0
216 rprintn()
217 suite_name = BuiltIn().get_variable_value("${suite_name}")
218
219 buffer = "\n"
220 buffer += gp.sindent(gp.sprint_time("Running test suite \"" +
221 suite_name + "\".\n"),
222 indent)
223 buffer += gp.sprint_pgm_header(indent, linefeed)
224
225 # Get value of global parm_list.
226 parm_list = BuiltIn().get_variable_value("${parm_list}")
227
228 buffer += sprint_vars(str(indent), str(loc_col1_width), *parm_list)
229 buffer += "\n"
230
Michael Walsha6723f22016-11-22 11:12:01 -0600231 # Setting global program_pid.
232 BuiltIn().set_global_variable("${program_pid}", os.getpid())
233
Michael Walsh18176322016-11-15 15:11:21 -0600234 return buffer
235
236###############################################################################
237
238
239###############################################################################
240def sprint_error_report(error_text="\n"):
241
242 r"""
243 Print a standardized error report that robot programs should print on
244 failure. The report includes useful information like error text, command
245 line, pid, userid, program parameters, etc. Callers must have declared a
246 @{parm_list} variable which contains the names of all program parameters.
247 """
248
Michael Walshafa7a1b2016-12-09 14:02:48 -0600249 try:
250 error_report_format = int(BuiltIn().get_variable_value(
251 "${error_report_format}"))
252 except TypeError:
253 error_report_format = 0
254
255 # Currently, supported values for error_report_format are:
256 # 0 - Short form
257 # 1 - Long form
258
259 error_text = error_text.rstrip('\n') + '\n'
260
261 if error_report_format == 0:
262 return gp.sprint_error(error_text)
263
Michael Walsh18176322016-11-15 15:11:21 -0600264 buffer = ""
265 buffer += gp.sprint_dashes(width=120, char="=")
266 buffer += gp.sprint_error(error_text)
267
268 indent = 2
269 linefeed = 0
270
271 buffer += sprint_pgm_header(indent)
272
273 buffer += gp.sprint_dashes(width=120, char="=")
274
275 return buffer
276
277###############################################################################
278
279
280###############################################################################
281def sprint_issuing_keyword(cmd_buf,
282 test_mode=0):
283
284 r"""
285 Return a line indicating a robot command (i.e. keyword + args) that the
286 program is about to execute.
287
288 For example, for the following robot code...
289
290 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1
291 rdprint_issuing_keyword
292
293 The output would look something like this:
294
295 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1
296
297 Description of args:
298 cmd_buf A list containing the keyword and
299 arguments to be run.
300 """
301
302 buffer = ""
303 cmd_buf_str = ' '.join([str(element) for element in cmd_buf])
304 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode))
305
306 return buffer
307
308###############################################################################
309
310
311###############################################################################
312def sprint_auto_vars(headers=0):
313
314 r"""
315 This keyword will string print all of the Automatic Variables described in
316 the Robot User's Guide using rprint_vars.
Michael Walshde791732016-09-06 14:25:24 -0500317
318 NOTE: Not all automatic variables are guaranteed to exist.
319
320 Description of arguments:
321 headers This indicates that a header and footer
Michael Walsh18176322016-11-15 15:11:21 -0600322 should be printed.
Michael Walshde791732016-09-06 14:25:24 -0500323 """
324
Michael Walsh18176322016-11-15 15:11:21 -0600325 buffer = ""
Michael Walshde791732016-09-06 14:25:24 -0500326 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600327 buffer += gp.sprint_dashes()
328 buffer += "Automatic Variables:"
Michael Walshde791732016-09-06 14:25:24 -0500329
Michael Walsh18176322016-11-15 15:11:21 -0600330 buffer += \
331 sprint_vars(
332 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS",
333 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE",
334 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE",
335 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION",
336 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE",
337 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE",
338 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR")
Michael Walshde791732016-09-06 14:25:24 -0500339
340 if int(headers) == 1:
Michael Walsh18176322016-11-15 15:11:21 -0600341 buffer += gp.sprint_dashes()
342
343 return buffer
Michael Walshde791732016-09-06 14:25:24 -0500344
345###############################################################################
346
347
348###############################################################################
Michael Walsh18176322016-11-15 15:11:21 -0600349# In the following section of code, we will dynamically create robot versions
350# of print functions for each of the sprint functions defined in the
351# gen_print.py module. So, for example, where we have an sprint_time()
352# function defined above that returns the time to the caller in a string, we
353# will create a corresponding rprint_time() function that will print that
354# string directly to stdout.
Michael Walshde791732016-09-06 14:25:24 -0500355
Michael Walsh18176322016-11-15 15:11:21 -0600356# It can be complicated to follow what's being created by the exec statement
357# below. Here is an example of the rprint_time() function that will be
358# created (as of the time of this writing):
Michael Walshde791732016-09-06 14:25:24 -0500359
Michael Walsh18176322016-11-15 15:11:21 -0600360# def rprint_time(*args):
361# s_func = getattr(gp, "sprint_time")
362# BuiltIn().log_to_console(s_func(*args),
363# stream='STDIN',
364# no_newline=True)
Michael Walshde791732016-09-06 14:25:24 -0500365
Michael Walsh18176322016-11-15 15:11:21 -0600366# Here are comments describing the lines in the body of the created function.
367# Put a reference to the "s" version of this function in s_func.
368# Call the "s" version of this function passing it all of our arguments. Log
369# the result to the console.
Michael Walshde791732016-09-06 14:25:24 -0500370
Michael Walsh18176322016-11-15 15:11:21 -0600371robot_prefix = "r"
372robot_func_names =\
373 [
374 'print_error_report', 'print_pgm_header',
375 'print_issuing_keyword', 'print_vars', 'print_auto_vars'
376 ]
377func_names = gp.func_names + robot_func_names
Michael Walsha6723f22016-11-22 11:12:01 -0600378
Michael Walshafa7a1b2016-12-09 14:02:48 -0600379explicit_definitions = ['print', 'printn']
380
Michael Walsha6723f22016-11-22 11:12:01 -0600381func_names = list(my_ord_dict.fromkeys(func_names))
382
383if gen_robot_print_debug:
384 rprintn()
385 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True)
386 rprintn()
387
Michael Walsh18176322016-11-15 15:11:21 -0600388for func_name in func_names:
Michael Walshde791732016-09-06 14:25:24 -0500389
Michael Walshafa7a1b2016-12-09 14:02:48 -0600390 if func_name not in explicit_definitions:
391 # The print_var function's job is to figure out the name of arg 1 and
392 # then call print_varx. This is not currently supported for robot
393 # programs. Though it IS supported for python modules.
394 if func_name == "print_error" or func_name == "print_error_report":
395 output_stream = "STDERR"
396 else:
397 output_stream = "STDIN"
398 if func_name in robot_func_names:
399 object_name = "__import__(__name__)"
400 else:
401 object_name = "gp"
402 func_def = \
403 [
404 "def " + robot_prefix + func_name + "(*args):",
405 " s_func = getattr(" + object_name + ", \"s" + func_name +
406 "\")",
407 " BuiltIn().log_to_console(s_func(*args),"
408 " stream='" + output_stream + "',"
409 " no_newline=True)"
410 ]
411
412 pgm_definition_string = '\n'.join(func_def)
413 if gen_robot_print_debug:
414 rprintn()
415 rprintn(pgm_definition_string)
416 exec(pgm_definition_string)
Michael Walsh18176322016-11-15 15:11:21 -0600417
418 # Now define "q" versions of each print function. The q functions only
419 # print if global robot var "quiet" is 0. If the global var quiet is not
420 # defined, it will be treated as though it were "1", i.e. no printing will
421 # be done.
422 func_def = \
423 [
424 "def rq" + func_name + "(*args):",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600425 " if get_quiet():",
426 " return",
427 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600428 ]
429
430 pgm_definition_string = '\n'.join(func_def)
431 if gen_robot_print_debug:
432 rprintn(pgm_definition_string)
433 exec(pgm_definition_string)
434
435 # Now define "d" versions of each print function. The d functions only
436 # print if global robot var "debug" is 1.
437 func_def = \
438 [
439 "def rd" + func_name + "(*args):",
Michael Walshafa7a1b2016-12-09 14:02:48 -0600440 " if not get_debug():",
441 " return",
442 " r" + func_name + "(*args)"
Michael Walsh18176322016-11-15 15:11:21 -0600443 ]
444
445 pgm_definition_string = '\n'.join(func_def)
446 if gen_robot_print_debug:
447 rprintn(pgm_definition_string)
448 exec(pgm_definition_string)
449
Michael Walshafa7a1b2016-12-09 14:02:48 -0600450 # Create shorter aliases.
Michael Walsha6723f22016-11-22 11:12:01 -0600451 prefixes = ["", "q", "d"]
Michael Walsh18176322016-11-15 15:11:21 -0600452 alias = re.sub("print_", "p", func_name)
Michael Walsha6723f22016-11-22 11:12:01 -0600453 for prefix2 in prefixes:
454 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\
455 prefix2 + func_name
456 if gen_robot_print_debug:
457 rprintn(cmd_buf)
458 exec(cmd_buf)
Michael Walsh18176322016-11-15 15:11:21 -0600459
460# Define an alias. rpvar is just a special case of rpvars where the args
461# list contains only one element.
462cmd_buf = "rpvar = rpvars"
463if gen_robot_print_debug:
Michael Walsha6723f22016-11-22 11:12:01 -0600464 rprintn()
Michael Walsh18176322016-11-15 15:11:21 -0600465 rprintn(cmd_buf)
466exec(cmd_buf)
Michael Walshde791732016-09-06 14:25:24 -0500467
468###############################################################################