1#!/usr/bin/env python 2 3r""" 4This file contains functions useful for printing to stdout from robot programs. 5""" 6 7import sys 8import re 9import os 10 11try: 12 from robot.utils import DotDict as my_ord_dict 13except ImportError: 14 from collections import OrderedDict as my_ord_dict 15 16import gen_print as gp 17 18from robot.libraries.BuiltIn import BuiltIn 19from robot.api import logger 20 21try: 22 # The user can set environment variable "GEN_ROBOT_PRINT_DEBUG" to get 23 # debug output from this module. 24 gen_robot_print_debug = int(os.environ['GEN_ROBOT_PRINT_DEBUG']) 25except KeyError: 26 gen_robot_print_debug = 0 27 28 29############################################################################### 30def 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############################################################################### 59def set_quiet_default(quiet=None, 60 default=0): 61 62 r""" 63 Return a default value for the quiet variable based on its current value, 64 the value of global ${QUIET} and default. 65 66 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 """ 74 75 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) 82 83 return quiet 84 85############################################################################### 86 87 88############################################################################### 89def 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############################################################################### 133def rprint(buffer="", 134 stream="STDOUT"): 135 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 140 keyword is essentially an alias for "Log to Console <string> <stream>". 141 142 Description of arguments: 143 buffer The value that is to written to stdout. 144 """ 145 146 BuiltIn().log_to_console(gp.replace_passwords(str(buffer)), 147 no_newline=True, stream=stream) 148 149############################################################################### 150 151 152############################################################################### 153def rprintn(buffer="", 154 stream='STDOUT'): 155 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 159 an abbreviated form of "Log go Console <string> <stream>" 160 161 Description of arguments: 162 buffer The value that is to written to stdout. 163 """ 164 165 BuiltIn().log_to_console(gp.replace_passwords(buffer), no_newline=False, 166 stream=stream) 167 168############################################################################### 169 170 171############################################################################### 172def sprint_vars(*args): 173 174 r""" 175 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 183 "hex" value. 184 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. 188 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 198 # 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". 207 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 214 # See if parm 3 is to be interpreted as "col1_width". 215 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 222 buffer = "" 223 for var_name in args_list: 224 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}") 225 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 # This function is deprecated since the caller may now call the gen_print 245 # version directly. 246 return gp.sprint_pgm_header(indent, linefeed=1) 247 248############################################################################### 249 250 251############################################################################### 252def sprint_error_report(error_text="\n"): 253 254 r""" 255 Print a standardized error report that robot programs should print on 256 failure. The report includes useful information like error text, command 257 line, pid, userid, program parameters, etc. Callers must have declared a 258 @{parm_list} variable which contains the names of all program parameters. 259 """ 260 261 # This function is deprecated. The caller is advised to call the 262 # gen_print version of this function directly. 263 264 return gp.sprint_error_report(error_text) 265 266############################################################################### 267 268 269############################################################################### 270def sprint_issuing_keyword(cmd_buf, 271 test_mode=0): 272 273 r""" 274 Return a line indicating a robot command (i.e. keyword + args) that the 275 program is about to execute. 276 277 For example, for the following robot code... 278 279 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1 280 rdprint_issuing_keyword 281 282 The output would look something like this: 283 284 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1 285 286 Description of args: 287 cmd_buf A list containing the keyword and 288 arguments to be run. 289 """ 290 291 buffer = "" 292 cmd_buf_str = ' '.join([str(element) for element in cmd_buf]) 293 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode)) 294 295 return buffer 296 297############################################################################### 298 299 300############################################################################### 301def sprint_auto_vars(headers=0): 302 303 r""" 304 This keyword will string print all of the Automatic Variables described in 305 the Robot User's Guide using rprint_vars. 306 307 NOTE: Not all automatic variables are guaranteed to exist. 308 309 Description of arguments: 310 headers This indicates that a header and footer 311 should be printed. 312 """ 313 314 buffer = "" 315 if int(headers) == 1: 316 buffer += gp.sprint_dashes() 317 buffer += "Automatic Variables:" 318 319 buffer += \ 320 sprint_vars( 321 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS", 322 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE", 323 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE", 324 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION", 325 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE", 326 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE", 327 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR") 328 329 if int(headers) == 1: 330 buffer += gp.sprint_dashes() 331 332 return buffer 333 334############################################################################### 335 336 337############################################################################### 338# In the following section of code, we will dynamically create robot versions 339# of print functions for each of the sprint functions defined in the 340# gen_print.py module. So, for example, where we have an sprint_time() 341# function defined above that returns the time to the caller in a string, we 342# will create a corresponding rprint_time() function that will print that 343# string directly to stdout. 344 345# It can be complicated to follow what's being created by the exec statement 346# below. Here is an example of the rprint_time() function that will be 347# created (as of the time of this writing): 348 349# def rprint_time(*args): 350# s_func = getattr(gp, "sprint_time") 351# BuiltIn().log_to_console(s_func(*args), 352# stream='STDIN', 353# no_newline=True) 354 355# Here are comments describing the lines in the body of the created function. 356# Put a reference to the "s" version of this function in s_func. 357# Call the "s" version of this function passing it all of our arguments. Log 358# the result to the console. 359 360robot_prefix = "r" 361robot_func_names =\ 362 [ 363 'print_error_report', 'print_pgm_header', 364 'print_issuing_keyword', 'print_vars', 'print_auto_vars' 365 ] 366func_names = gp.func_names + robot_func_names 367 368explicit_definitions = ['print', 'printn'] 369 370func_names = list(my_ord_dict.fromkeys(func_names)) 371 372if gen_robot_print_debug: 373 rprintn() 374 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True) 375 rprintn() 376 377for func_name in func_names: 378 379 if func_name not in explicit_definitions: 380 # The print_var function's job is to figure out the name of arg 1 and 381 # then call print_varx. This is not currently supported for robot 382 # programs. Though it IS supported for python modules. 383 if func_name == "print_error" or func_name == "print_error_report": 384 output_stream = "STDERR" 385 else: 386 output_stream = "STDIN" 387 if func_name in robot_func_names: 388 object_name = "__import__(__name__)" 389 else: 390 object_name = "gp" 391 func_def = \ 392 [ 393 "def " + robot_prefix + func_name + "(*args):", 394 " s_func = getattr(" + object_name + ", \"s" + func_name + 395 "\")", 396 " BuiltIn().log_to_console" + 397 "(gp.replace_passwords(s_func(*args))," 398 " stream='" + output_stream + "'," 399 " no_newline=True)" 400 ] 401 402 pgm_definition_string = '\n'.join(func_def) 403 if gen_robot_print_debug: 404 rprintn() 405 rprintn(pgm_definition_string) 406 exec(pgm_definition_string) 407 408 # Now define "q" versions of each print function. The q functions only 409 # print if global robot var "quiet" is 0. If the global var quiet is not 410 # defined, it will be treated as though it were "1", i.e. no printing will 411 # be done. 412 func_def = \ 413 [ 414 "def rq" + func_name + "(*args):", 415 " if get_quiet():", 416 " return", 417 " r" + func_name + "(*args)" 418 ] 419 420 pgm_definition_string = '\n'.join(func_def) 421 if gen_robot_print_debug: 422 rprintn(pgm_definition_string) 423 exec(pgm_definition_string) 424 425 # Now define "d" versions of each print function. The d functions only 426 # print if global robot var "debug" is 1. 427 func_def = \ 428 [ 429 "def rd" + func_name + "(*args):", 430 " if not get_debug():", 431 " return", 432 " r" + func_name + "(*args)" 433 ] 434 435 pgm_definition_string = '\n'.join(func_def) 436 if gen_robot_print_debug: 437 rprintn(pgm_definition_string) 438 exec(pgm_definition_string) 439 440 # Create shorter aliases. 441 prefixes = ["", "q", "d"] 442 alias = re.sub("print_", "p", func_name) 443 for prefix2 in prefixes: 444 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\ 445 prefix2 + func_name 446 if gen_robot_print_debug: 447 rprintn(cmd_buf) 448 exec(cmd_buf) 449 450# Define an alias. rpvar is just a special case of rpvars where the args 451# list contains only one element. 452cmd_buf = "rpvar = rpvars" 453if gen_robot_print_debug: 454 rprintn() 455 rprintn(cmd_buf) 456exec(cmd_buf) 457 458############################################################################### 459