Skip to content

Instantly share code, notes, and snippets.

@tstone2077
Last active June 1, 2019 15:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tstone2077/4532404 to your computer and use it in GitHub Desktop.
Save tstone2077/4532404 to your computer and use it in GitHub Desktop.
Template for a python tool. This template supports:* running on the command line or importing* alternate return codes* argument parsing and validating* logging
# vim: set fileencoding=utf-8
import argparse
import logging
import os
import sys
import json
# -------------------
__doc__ = """
Enter description here
"""
__author__ = 'Thurston Stone'
__versioninfo__ = (0, 1, 0)
__version__ = '.'.join(map(str, __versioninfo__))
INVALID_USAGE_RETURN_CODE = 2
UNCAUGHT_EXCEPTION = 3
SCRIPT_FILE = os.path.basename(os.path.abspath(__file__))
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
class UsageError(Exception):
""" Exception class when the file is used incorrectly on the command line
"""
def __init__(self, parser, error):
self.parser = parser
self.error = error
def __str__(self):
return "%s\nERROR: %s" % (self.parser.format_usage(), self.error)
def ValidateArgs(argv):
"""
Function: validateArgs():
will validate the command line arguments and options passed.
it returns opts,args
"""
# First, create a parser to check for the config file.
# If a config file argument exists, then we will want to
# use it to inform the main parser
confParser = argparse.ArgumentParser(add_help=False)
confParser.add_argument("-c",
"--config-file",
type=argparse.FileType("r"),
help="Path to file containing configuration data.")
args = confParser.parse_known_args()[0]
formatter = argparse.RawTextHelpFormatter
parser = argparse.ArgumentParser(description=__doc__, parents=[confParser],
formatter_class=formatter)
# Set defaults here instead of in the add_argument function.
# This is to prevent the add_function default from overriding
# the defaults set in the set_defaults functions.
defaults = {
'verbose': 'ERROR',
}
if args.config_file:
# Parse the config file as a json file
jsonInput = json.load(args.config_file)
# Edit the defaults dictionary based on config contents
for name,value in jsonInput.items():
defaults[name.replace("-", "_")] = value
# set the defaults from the dictionary
parser.set_defaults(**defaults)
# general options
parser.add_argument("-v",
"--verbose",
# default="ERROR", do not set default here.
# required=True, do not set required here.
const="INFO",
nargs="?",
help="Level of verbose output to Display to stdout"
"(DEBUG, INFO, WARNING, ERROR, CRITICAL, FATAL)")
args = parser.parse_args(argv[1:])
error = None
"""
Place any error checking here. If an error occurred, set the error
variable.
"""
# check required elements here
if args.verbose is None:
error = "verbose must be set."
if error is not None:
raise UsageError(parser, error)
return args
class Application(object):
def __init__(self):
logging.debug("Initializing Application...")
def Run(self):
logging.debug("Running Application...")
def Main(argv):
"""
The main function. This function will run if the command line is called as
opposed to this file being imported.
"""
args = ValidateArgs(argv)
level = getattr(logging, args.verbose.upper())
logging.basicConfig(level=level,
format='%(module)s(%(lineno)d)|%(asctime)s|' +
'%(threadName)s|%(levelname)s| %(message)s')
logging.debug("Python %s" % sys.version)
app = Application()
app.Run()
return 0
# if this program is run on the command line, run the main function
if __name__ == '__main__':
showTraceback = False
if '--show-traceback' in sys.argv:
showTraceback = True
del sys.argv[sys.argv.index('--show-traceback')]
try:
returnCode = Main(sys.argv)
except Exception as e:
if showTraceback:
raise
print("Uncaught Exception: %s: %s" % (type(e), e))
returnCode = UNCAUGHT_EXCEPTION
sys.exit(returnCode)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment