blob: d8363c3339aad783f7712ef07e1cbfaad12a5955 [file] [log] [blame]
Michael Walsh7423c012016-10-04 10:27:21 -05001#!/usr/bin/env python
2
3r"""
4This module provides valuable argument processing functions like
5gen_get_options and sprint_args.
6"""
7
8import sys
George Keishing3b7115a2018-08-02 10:48:17 -05009try:
10 import __builtin__
11except ImportError:
12 import builtins as __builtin__
Michael Walsh7423c012016-10-04 10:27:21 -050013import atexit
14import signal
15import argparse
16
17import gen_print as gp
Michael Walsh69d58ae2018-06-01 15:18:57 -050018import gen_valid as gv
Michael Walsh7423c012016-10-04 10:27:21 -050019
20default_string = ' The default value is "%(default)s".'
21
22
Michael Walsh7423c012016-10-04 10:27:21 -050023def gen_get_options(parser,
24 stock_list=[]):
Michael Walsh7423c012016-10-04 10:27:21 -050025 r"""
26 Parse the command line arguments using the parser object passed and return
Michael Walsh69d58ae2018-06-01 15:18:57 -050027 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:
Michael Walsh7423c012016-10-04 10:27:21 -050029
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:
Michael Walsh69d58ae2018-06-01 15:18:57 -050057 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)
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050063 if isinstance(stock_list[ix], tuple):
Michael Walsh7423c012016-10-04 10:27:21 -050064 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:
Michael Walsh69d58ae2018-06-01 15:18:57 -050071 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)
Michael Walsh7423c012016-10-04 10:27:21 -050075
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],
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050084 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)
Michael Walsh7423c012016-10-04 10:27:21 -050088 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],
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -050096 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)
Michael Walsh7423c012016-10-04 10:27:21 -0500100 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],
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500108 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)
Michael Walsh7423c012016-10-04 10:27:21 -0500111 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'],
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500120 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)
Michael Walsh7423c012016-10-04 10:27:21 -0500123
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)):
Joy Onyerikwu004ad3c2018-06-11 16:29:56 -0500131 if isinstance(stock_list[ix], tuple):
Michael Walsh7423c012016-10-04 10:27:21 -0500132 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
Michael Walsh7423c012016-10-04 10:27:21 -0500159
Michael Walshc33ef372017-01-10 11:46:29 -0600160def set_pgm_arg(var_value,
161 var_name=None):
Michael Walshc33ef372017-01-10 11:46:29 -0600162 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
Michael Walshc33ef372017-01-10 11:46:29 -0600186
Michael Walsh7423c012016-10-04 10:27:21 -0500187def sprint_args(arg_obj,
188 indent=0):
Michael Walsh7423c012016-10-04 10:27:21 -0500189 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
Michael Walsh0d5f96a2019-05-20 10:09:57 -0500200 col1_width = gp.dft_col1_width + indent
Michael Walshbec416d2016-11-10 08:54:52 -0600201
Michael Walsh7423c012016-10-04 10:27:21 -0500202 buffer = ""
Michael Walsh7423c012016-10-04 10:27:21 -0500203 for key in arg_obj.__dict__:
Michael Walshbec416d2016-11-10 08:54:52 -0600204 buffer += gp.sprint_varx(key, getattr(arg_obj, key), 0, indent,
Michael Walsh0d5f96a2019-05-20 10:09:57 -0500205 col1_width)
Michael Walsh7423c012016-10-04 10:27:21 -0500206 return buffer
207
Michael Walsh7423c012016-10-04 10:27:21 -0500208
Michael Walsh5328f382019-09-13 14:18:55 -0500209module = 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
Michael Walsh7423c012016-10-04 10:27:21 -0500248def gen_post_validation(exit_function=None,
249 signal_handler=None):
Michael Walsh7423c012016-10-04 10:27:21 -0500250 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
Michael Walsh5328f382019-09-13 14:18:55 -0500261 exit function. This defaults to this
262 module's gen_exit_function.
Michael Walsh7423c012016-10-04 10:27:21 -0500263 signal_handler A function object pointing to the caller's
Michael Walsh5328f382019-09-13 14:18:55 -0500264 signal_handler function. This defaults to
265 this module's gen_signal_handler.
Michael Walsh7423c012016-10-04 10:27:21 -0500266 """
267
Michael Walsh5328f382019-09-13 14:18:55 -0500268 # 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()