Created
January 30, 2022 14:57
-
-
Save DS256/b2d9293563254f6bd1b22ca5f5b670a7 to your computer and use it in GitHub Desktop.
Simple Python Template With Argument Parsing and Logging
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# TEMPLATE_1.PY | |
# This program template was created to be simple single program. | |
# I didn't want to get around to having the complexity of a Python project. | |
# I am greatful to the following contributors who I stole code from ;-) | |
# - https://gist.github.com/calebrob6/eb98725187425c527567#file-template-py | |
# - https://gist.github.com/nafeu/e513e23b6b343ef896e4cccd4430b428 | |
import sys,os | |
import time | |
import argparse | |
import logging | |
__program__ = "Template" | |
__author__ = "John Doe" | |
__copyright__ = "Copyright 2022, John Doe" | |
__credits__ = ["John Doe"] | |
__license__ = "" | |
__version__ = "1.0" | |
__maintainer__ = "John Doe" | |
__email__ = "[email protected]" | |
__status__ = "Development" | |
# The following special names are defined because I could not find an import | |
# of return codes when terminating the program. I haven't tried it yet, but | |
# __FAILURE__ should be able to be trapped in a shell script. | |
__success__ = 0 | |
__failure__ = 1 | |
#************************************************************************************************ | |
# https://docs.python.org/3/library/argparse.html | |
def doArgs(argList, name): | |
parser = argparse.ArgumentParser(description=name) | |
parser.add_argument('-v', "--verbose", action="store_true", help="Enable verbose information", default=False) | |
parser.add_argument('-d', "--debug", action="store_true", help="Enable debugging", default=False) | |
parser.add_argument('--input', action="store", dest="inputFn", type=str, help="Input file name", required=False) | |
parser.add_argument('--output', action="store", dest="outputFn", type=str, help="Output file name", required=False) | |
return parser.parse_args(argList) | |
#************************************************************************************************ | |
# Mainline Function Called From End of Program | |
#************************************************************************************************ | |
def main(): | |
startTime=time.time() # Used to calculate run-time of the program | |
progName = __program__ # I distinquish between the program name and | |
runName = sys.argv[0] # the name it may run under for testing. | |
# Start Logging | |
# Logging levels explained https://www.logicmonitor.com/blog/python-logging-levels-explained | |
# See https://docs.python.org/3/howto/logging-cookbook.html for other examples | |
# I haven't figured out a way to set 'logging.DEBUG' outside of the basicConfig call. However, | |
# I wanted to use it because it seemed easier than logging.logger() | |
logging.basicConfig(format="%(asctime)s:%(levelname)s:%(message)s",level=logging.DEBUG) | |
# logging.basicConfig(filename=runName+".log",format="%(asctime)s:%(levelname)s:%(message)s",level=logging.DEBUG) | |
# Parse Arguements | |
args = doArgs(sys.argv[1:], progName) | |
# Process/Validate Passed Arguements | |
# --verbose Provide some runtime information. | |
verbose = args.verbose | |
# --debug Provide information using for debugging | |
global debug | |
debug = args.debug | |
if debug: verbose = True | |
if verbose: logging.info("Started "+progName+" running as "+runName) | |
if debug: logging.debug("*** DEBUG MODE ***") | |
# --input inputFn NOT USED IN TEMPLATE PLACE HOLDER | |
input_specified = False # Indicates whether an INPUT FILE has been specified | |
if (args.inputFn is not None): | |
input_specified = True | |
inputFn = args.inputFn | |
if not os.path.isfile(inputFn): | |
logging.critical("Input file "+inputFn+" doesn't exist, exiting") | |
return __failure__ | |
# --output outputFn NOT USED IN TEMPLATE PLACE HOLDER | |
output_specified = False # Indicates whether an OUTPUT file has been specified. | |
if (args.outputFn is not None): | |
outputFn = args.outputFn | |
output_specified = True | |
outputBase = os.path.dirname(outputFn) | |
if outputBase!='' and not os.path.exists(outputBase): | |
logging.critical("Output directory "+outputBase+" doesn't exist, exiting") | |
return __failure__ | |
else: | |
if verbose: logging.info("Output to "+outputFn) | |
##### START OF MAINLINE CODE #### | |
##### END OF MAINLINE CODE #### | |
if verbose: logging.info("Finished in %0.4f seconds" % (time.time() - startTime) ) | |
return __success__ | |
#************************************************************************************************ | |
if __name__ == '__main__': | |
rtn=main() | |
if debug: logging.debug("Main() return value "+str(rtn)) | |
sys.exit(rtn) # User sys.exit() since it seems to invoke cleanup code. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment