1#!/usr/bin/env python 2 3r""" 4This module provides valuable argument processing functions like gen_get_options and sprint_args. 5""" 6 7import sys 8try: 9 import __builtin__ 10except ImportError: 11 import builtins as __builtin__ 12import atexit 13import signal 14import argparse 15 16import gen_print as gp 17import gen_valid as gv 18 19default_string = ' The default value is "%(default)s".' 20 21 22def gen_get_options(parser, 23 stock_list=[]): 24 r""" 25 Parse the command line arguments using the parser object passed and return True/False (i.e. pass/fail). 26 However, if gv.exit_on_error is set, simply exit the program on failure. Also set the following built in 27 values: 28 29 __builtin__.quiet This value is used by the qprint functions. 30 __builtin__.test_mode This value is used by command processing functions. 31 __builtin__.debug This value is used by the dprint functions. 32 __builtin__.arg_obj This value is used by print_program_header, etc. 33 __builtin__.parser This value is used by print_program_header, etc. 34 35 Description of arguments: 36 parser A parser object. See argparse module documentation for details. 37 stock_list The caller can use this parameter to request certain stock parameters 38 offered by this function. For example, this function will define a 39 "quiet" option upon request. This includes stop help text and parm 40 checking. The stock_list is a list of tuples each of which consists of 41 an arg_name and a default value. Example: stock_list = [("test_mode", 42 0), ("quiet", 1), ("debug", 0)] 43 """ 44 45 # This is a list of stock parms that we support. 46 master_stock_list = ["quiet", "test_mode", "debug", "loglevel"] 47 48 # Process stock_list. 49 for ix in range(0, len(stock_list)): 50 if len(stock_list[ix]) < 1: 51 error_message = "Programmer error - stock_list[" + str(ix) +\ 52 "] is supposed to be a tuple containing at" +\ 53 " least one element which is the name of" +\ 54 " the desired stock parameter:\n" +\ 55 gp.sprint_var(stock_list) 56 return gv.process_error_message(error_message) 57 if isinstance(stock_list[ix], tuple): 58 arg_name = stock_list[ix][0] 59 default = stock_list[ix][1] 60 else: 61 arg_name = stock_list[ix] 62 default = None 63 64 if arg_name not in master_stock_list: 65 error_message = "Programmer error - arg_name \"" + arg_name +\ 66 "\" not found found in stock list:\n" +\ 67 gp.sprint_var(master_stock_list) 68 return gv.process_error_message(error_message) 69 70 if arg_name == "quiet": 71 if default is None: 72 default = 0 73 parser.add_argument( 74 '--quiet', 75 default=default, 76 type=int, 77 choices=[1, 0], 78 help='If this parameter is set to "1", %(prog)s' 79 + ' will print only essential information, i.e. it will' 80 + ' not echo parameters, echo commands, print the total' 81 + ' run time, etc.' + default_string) 82 elif arg_name == "test_mode": 83 if default is None: 84 default = 0 85 parser.add_argument( 86 '--test_mode', 87 default=default, 88 type=int, 89 choices=[1, 0], 90 help='This means that %(prog)s should go through all the' 91 + ' motions but not actually do anything substantial.' 92 + ' This is mainly to be used by the developer of' 93 + ' %(prog)s.' + default_string) 94 elif arg_name == "debug": 95 if default is None: 96 default = 0 97 parser.add_argument( 98 '--debug', 99 default=default, 100 type=int, 101 choices=[1, 0], 102 help='If this parameter is set to "1", %(prog)s will print' 103 + ' additional debug information. This is mainly to be' 104 + ' used by the developer of %(prog)s.' + default_string) 105 elif arg_name == "loglevel": 106 if default is None: 107 default = "info" 108 parser.add_argument( 109 '--loglevel', 110 default=default, 111 type=str, 112 choices=['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL', 113 'debug', 'info', 'warning', 'error', 'critical'], 114 help='If this parameter is set to "1", %(prog)s will print' 115 + ' additional debug information. This is mainly to be' 116 + ' used by the developer of %(prog)s.' + default_string) 117 118 arg_obj = parser.parse_args() 119 120 __builtin__.quiet = 0 121 __builtin__.test_mode = 0 122 __builtin__.debug = 0 123 __builtin__.loglevel = 'WARNING' 124 for ix in range(0, len(stock_list)): 125 if isinstance(stock_list[ix], tuple): 126 arg_name = stock_list[ix][0] 127 default = stock_list[ix][1] 128 else: 129 arg_name = stock_list[ix] 130 default = None 131 if arg_name == "quiet": 132 __builtin__.quiet = arg_obj.quiet 133 elif arg_name == "test_mode": 134 __builtin__.test_mode = arg_obj.test_mode 135 elif arg_name == "debug": 136 __builtin__.debug = arg_obj.debug 137 elif arg_name == "loglevel": 138 __builtin__.loglevel = arg_obj.loglevel 139 140 __builtin__.arg_obj = arg_obj 141 __builtin__.parser = parser 142 143 # For each command line parameter, create a corresponding global variable and assign it the appropriate 144 # value. For example, if the command line contained "--last_name='Smith', we'll create a global variable 145 # named "last_name" with the value "Smith". 146 module = sys.modules['__main__'] 147 for key in arg_obj.__dict__: 148 setattr(module, key, getattr(__builtin__.arg_obj, key)) 149 150 return True 151 152 153def set_pgm_arg(var_value, 154 var_name=None): 155 r""" 156 Set the value of the arg_obj.__dict__ entry named in var_name with the var_value provided. Also, set 157 corresponding global variable. 158 159 Description of arguments: 160 var_value The value to set in the variable. 161 var_name The name of the variable to set. This defaults to the name of the 162 variable used for var_value when calling this function. 163 """ 164 165 if var_name is None: 166 var_name = gp.get_arg_name(None, 1, 2) 167 168 arg_obj.__dict__[var_name] = var_value 169 module = sys.modules['__main__'] 170 setattr(module, var_name, var_value) 171 if var_name == "quiet": 172 __builtin__.quiet = var_value 173 elif var_name == "debug": 174 __builtin__.debug = var_value 175 elif var_name == "test_mode": 176 __builtin__.test_mode = var_value 177 178 179def sprint_args(arg_obj, 180 indent=0): 181 r""" 182 sprint_var all of the arguments found in arg_obj and return the result as a string. 183 184 Description of arguments: 185 arg_obj An argument object such as is returned by the argparse parse_args() 186 method. 187 indent The number of spaces to indent each line of output. 188 """ 189 190 col1_width = gp.dft_col1_width + indent 191 192 buffer = "" 193 for key in arg_obj.__dict__: 194 buffer += gp.sprint_varx(key, getattr(arg_obj, key), 0, indent, 195 col1_width) 196 return buffer 197 198 199module = sys.modules["__main__"] 200 201 202def gen_exit_function(signal_number=0, 203 frame=None): 204 r""" 205 Execute whenever the program ends normally or with the signals that we catch (i.e. TERM, INT). 206 """ 207 208 gp.dprint_executing() 209 gp.dprint_var(signal_number) 210 211 # ignore_err influences the way shell_cmd processes errors. Since we're doing exit processing, we don't 212 # want to stop the program due to a shell_cmd failure. 213 ignore_err = 1 214 215 # Call the main module's exit_function if it is defined. 216 exit_function = getattr(module, "exit_function", None) 217 if exit_function: 218 exit_function(signal_number, frame) 219 220 gp.qprint_pgm_footer() 221 222 223def gen_signal_handler(signal_number, 224 frame): 225 r""" 226 Handle signals. Without a function to catch a SIGTERM or SIGINT, the program would terminate immediately 227 with return code 143 and without calling the exit_function. 228 """ 229 230 # The convention is to set up exit_function with atexit.register() so there is no need to explicitly 231 # call exit_function from here. 232 233 gp.dprint_executing() 234 235 # Calling exit prevents control from returning to the code that was running when the signal was received. 236 exit(0) 237 238 239def gen_post_validation(exit_function=None, 240 signal_handler=None): 241 r""" 242 Do generic post-validation processing. By "post", we mean that this is to be called from a validation 243 function after the caller has done any validation desired. If the calling program passes exit_function 244 and signal_handler parms, this function will register them. In other words, it will make the 245 signal_handler functions get called for SIGINT and SIGTERM and will make the exit_function function run 246 prior to the termination of the program. 247 248 Description of arguments: 249 exit_function A function object pointing to the caller's exit function. This defaults 250 to this module's gen_exit_function. 251 signal_handler A function object pointing to the caller's signal_handler function. This 252 defaults to this module's gen_signal_handler. 253 """ 254 255 # Get defaults. 256 exit_function = exit_function or gen_exit_function 257 signal_handler = signal_handler or gen_signal_handler 258 259 atexit.register(exit_function) 260 signal.signal(signal.SIGINT, signal_handler) 261 signal.signal(signal.SIGTERM, signal_handler) 262 263 264def gen_setup(): 265 r""" 266 Do general setup for a program. 267 """ 268 269 # Set exit_on_error for gen_valid functions. 270 gv.set_exit_on_error(True) 271 272 # Get main module variable values. 273 parser = getattr(module, "parser") 274 stock_list = getattr(module, "stock_list") 275 validate_parms = getattr(module, "validate_parms", None) 276 277 gen_get_options(parser, stock_list) 278 279 if validate_parms: 280 validate_parms() 281 gen_post_validation() 282 283 gp.qprint_pgm_header() 284