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