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 rprint(buffer="", 31 stream="STDOUT"): 32 33 r""" 34 rprint stands for "Robot Print". This keyword will print the user's 35 buffer to the console. This keyword does not write a linefeed. It is the 36 responsibility of the caller to include a line feed if desired. This 37 keyword is essentially an alias for "Log to Console <string> <stream>". 38 39 Description of arguments: 40 buffer The value that is to written to stdout. 41 """ 42 43 BuiltIn().log_to_console(gp.replace_passwords(str(buffer)), 44 no_newline=True, stream=stream) 45 46############################################################################### 47 48 49############################################################################### 50def rprintn(buffer="", 51 stream='STDOUT'): 52 53 r""" 54 rprintn stands for "Robot print with linefeed". This keyword will print 55 the user's buffer to the console along with a linefeed. It is basically 56 an abbreviated form of "Log go Console <string> <stream>" 57 58 Description of arguments: 59 buffer The value that is to written to stdout. 60 """ 61 62 BuiltIn().log_to_console(gp.replace_passwords(buffer), no_newline=False, 63 stream=stream) 64 65############################################################################### 66 67 68############################################################################### 69def sprint_vars(*args): 70 71 r""" 72 sprint_vars stands for "String Print Vars". This is a robot redefinition 73 of the sprint_vars function in gen_print.py. Given a list of variable 74 names, this keyword will string print each variable name and value such 75 that the value lines up in the same column as messages printed with rptime. 76 77 Description of arguments: 78 args: 79 If the first argument is an integer, it will be interpreted to be the 80 "hex" value. 81 If the second argument is an integer, it will be interpreted to be the 82 "indent" value. 83 If the third argument is an integer, it will be interpreted to be the 84 "col1_width" value. 85 All remaining parms are considered variable names which are to be 86 sprinted. 87 """ 88 89 if len(args) == 0: 90 return 91 92 # Create list from args (which is a tuple) so that it can be modified. 93 args_list = list(args) 94 95 # See if parm 1 is to be interpreted as "hex". 96 try: 97 if type(int(args_list[0])) is int: 98 hex = int(args_list[0]) 99 args_list.pop(0) 100 except ValueError: 101 hex = 0 102 103 # See if parm 2 is to be interpreted as "indent". 104 try: 105 if type(int(args_list[0])) is int: 106 indent = int(args_list[0]) 107 args_list.pop(0) 108 except ValueError: 109 indent = 0 110 111 # See if parm 3 is to be interpreted as "col1_width". 112 try: 113 if type(int(args_list[0])) is int: 114 loc_col1_width = int(args_list[0]) 115 args_list.pop(0) 116 except ValueError: 117 loc_col1_width = gp.col1_width 118 119 buffer = "" 120 for var_name in args_list: 121 var_value = BuiltIn().get_variable_value("${" + str(var_name) + "}") 122 buffer += gp.sprint_varx(var_name, var_value, hex, indent, 123 loc_col1_width) 124 125 return buffer 126 127############################################################################### 128 129 130############################################################################### 131def sprint_pgm_header(indent=0): 132 133 r""" 134 Sprint a standardized header that robot programs should print at the 135 beginning of the run. The header includes useful information like command 136 line, pid, userid, program parameters, etc. Callers need to have declared 137 a global @{parm_list} variable which contains the names of all program 138 parameters. 139 """ 140 141 # This function is deprecated since the caller may now call the gen_print 142 # version directly. 143 return gp.sprint_pgm_header(indent, linefeed=1) 144 145############################################################################### 146 147 148############################################################################### 149def sprint_error_report(error_text="\n"): 150 151 r""" 152 Print a standardized error report that robot programs should print on 153 failure. The report includes useful information like error text, command 154 line, pid, userid, program parameters, etc. Callers must have declared a 155 @{parm_list} variable which contains the names of all program parameters. 156 """ 157 158 # This function is deprecated. The caller is advised to call the 159 # gen_print version of this function directly. 160 161 return gp.sprint_error_report(error_text) 162 163############################################################################### 164 165 166############################################################################### 167def sprint_issuing_keyword(cmd_buf, 168 test_mode=0): 169 170 r""" 171 Return a line indicating a robot command (i.e. keyword + args) that the 172 program is about to execute. 173 174 For example, for the following robot code... 175 176 @{cmd_buf}= Set Variable Set Environment Variable VAR1 1 177 rdprint_issuing_keyword 178 179 The output would look something like this: 180 181 #(CDT) 2016/10/27 12:04:21 - Issuing: Set Environment Variable VAR1 1 182 183 Description of args: 184 cmd_buf A list containing the keyword and 185 arguments to be run. 186 """ 187 188 buffer = "" 189 cmd_buf_str = ' '.join([str(element) for element in cmd_buf]) 190 buffer += gp.sprint_issuing(cmd_buf_str, int(test_mode)) 191 192 return buffer 193 194############################################################################### 195 196 197############################################################################### 198def sprint_auto_vars(headers=0): 199 200 r""" 201 This keyword will string print all of the Automatic Variables described in 202 the Robot User's Guide using rprint_vars. 203 204 NOTE: Not all automatic variables are guaranteed to exist. 205 206 Description of arguments: 207 headers This indicates that a header and footer 208 should be printed. 209 """ 210 211 buffer = "" 212 if int(headers) == 1: 213 buffer += gp.sprint_dashes() 214 buffer += "Automatic Variables:" 215 216 buffer += \ 217 sprint_vars( 218 "TEST_NAME", "TEST_TAGS", "TEST_DOCUMENTATION", "TEST_STATUS", 219 "TEST_DOCUMENTATION", "TEST_STATUS", "TEST_MESSAGE", 220 "PREV_TEST_NAME", "PREV_TEST_STATUS", "PREV_TEST_MESSAGE", 221 "SUITE_NAME", "SUITE_SOURCE", "SUITE_DOCUMENTATION", 222 "SUITE_METADATA", "SUITE_STATUS", "SUITE_MESSAGE", 223 "KEYWORD_STATUS", "KEYWORD_MESSAGE", "LOG_LEVEL", "OUTPUT_FILE", 224 "LOG_FILE", "REPORT_FILE", "DEBUG_FILE", "OUTPUT_DIR") 225 226 if int(headers) == 1: 227 buffer += gp.sprint_dashes() 228 229 return buffer 230 231############################################################################### 232 233 234############################################################################### 235# In the following section of code, we will dynamically create robot versions 236# of print functions for each of the sprint functions defined in the 237# gen_print.py module. So, for example, where we have an sprint_time() 238# function defined above that returns the time to the caller in a string, we 239# will create a corresponding rprint_time() function that will print that 240# string directly to stdout. 241 242# It can be complicated to follow what's being created by the exec statement 243# below. Here is an example of the rprint_time() function that will be 244# created (as of the time of this writing): 245 246# def rprint_time(*args): 247# s_func = getattr(gp, "sprint_time") 248# BuiltIn().log_to_console(s_func(*args), 249# stream='STDIN', 250# no_newline=True) 251 252# Here are comments describing the lines in the body of the created function. 253# Put a reference to the "s" version of this function in s_func. 254# Call the "s" version of this function passing it all of our arguments. Log 255# the result to the console. 256 257robot_prefix = "r" 258robot_func_names =\ 259 [ 260 'print_error_report', 'print_pgm_header', 261 'print_issuing_keyword', 'print_vars', 'print_auto_vars' 262 ] 263func_names = gp.func_names + robot_func_names 264 265explicit_definitions = ['print', 'printn'] 266 267func_names = list(my_ord_dict.fromkeys(func_names)) 268 269if gen_robot_print_debug: 270 rprintn() 271 BuiltIn().log_to_console(gp.sprint_var(func_names), no_newline=True) 272 rprintn() 273 274for func_name in func_names: 275 276 if func_name not in explicit_definitions: 277 # The print_var function's job is to figure out the name of arg 1 and 278 # then call print_varx. This is not currently supported for robot 279 # programs. Though it IS supported for python modules. 280 if func_name == "print_error" or func_name == "print_error_report": 281 output_stream = "STDERR" 282 else: 283 output_stream = "STDIN" 284 if func_name in robot_func_names: 285 object_name = "__import__(__name__)" 286 else: 287 object_name = "gp" 288 func_def = \ 289 [ 290 "def " + robot_prefix + func_name + "(*args):", 291 " s_func = getattr(" + object_name + ", \"s" + func_name + 292 "\")", 293 " BuiltIn().log_to_console" + 294 "(gp.replace_passwords(s_func(*args))," 295 " stream='" + output_stream + "'," 296 " no_newline=True)" 297 ] 298 299 pgm_definition_string = '\n'.join(func_def) 300 if gen_robot_print_debug: 301 rprintn() 302 rprintn(pgm_definition_string) 303 exec(pgm_definition_string) 304 305 # Now define "q" versions of each print function. The q functions only 306 # print if global robot var "quiet" is 0. If the global var quiet is not 307 # defined, it will be treated as though it were "1", i.e. no printing will 308 # be done. 309 func_def = \ 310 [ 311 "def rq" + func_name + "(*args):", 312 " if int(gp.get_var_value(None, 0, \"quiet\")): return", 313 " r" + func_name + "(*args)" 314 ] 315 316 pgm_definition_string = '\n'.join(func_def) 317 if gen_robot_print_debug: 318 rprintn(pgm_definition_string) 319 exec(pgm_definition_string) 320 321 # Now define "d" versions of each print function. The d functions only 322 # print if global robot var "debug" is 1. 323 func_def = \ 324 [ 325 "def rd" + func_name + "(*args):", 326 " if not int(gp.get_var_value(None, 0, \"debug\")): return", 327 " r" + func_name + "(*args)" 328 ] 329 330 pgm_definition_string = '\n'.join(func_def) 331 if gen_robot_print_debug: 332 rprintn(pgm_definition_string) 333 exec(pgm_definition_string) 334 335 # Create shorter aliases. 336 prefixes = ["", "q", "d"] 337 alias = re.sub("print_", "p", func_name) 338 for prefix2 in prefixes: 339 cmd_buf = robot_prefix + prefix2 + alias + " = " + robot_prefix +\ 340 prefix2 + func_name 341 if gen_robot_print_debug: 342 rprintn(cmd_buf) 343 exec(cmd_buf) 344 345# Define an alias. rpvar is just a special case of rpvars where the args 346# list contains only one element. 347cmd_buf = "rpvar = rpvars" 348if gen_robot_print_debug: 349 rprintn() 350 rprintn(cmd_buf) 351exec(cmd_buf) 352 353############################################################################### 354