"""
PyOpts.py
Author: AJ Mayorga
A highlevel quick wrapper for simplifying commandline options/arg handling
FEATURES:
- Generates shorts, longs and help/usage automatically
- Allows for specification of required options/args or groups there of
in addition to exclusionary opt/args or groups.
- Configures default values and selects/"choices"
- Returns a simple dictionary with key of supplied key name and value of configured type
DETAILS AND SUCH:
By passing a dict of args that are normally present & you will use in your code anyway.
The arg dict is given a key name & initialize each with its own config dict consisting of
the following keys and values.
PROJECT KEYS:
About is an about section that will be used as a header for
the generated usage called by -h/--help
ExitOnErr if True when and error or exception is found in processing the opt/args
an error message will be generated (if Quiet=False) followed by sys.exit()
Quiet toggles error/exception message output
Minimum the minimum number of required opt/args. This is for trivial commandline
requirements. 0 indicates no min required.
All other provided keys are considered option keys the provided names for which will be used
to derive shorts '-p' and longs '--port'. Each option key's value is initialized with a
configuration dict.
CONFIG DICT:
GID group identifier for a vars used by REQ Can be alpha/num value
REQ indicates variable requirement when not present False is default
- True indicates an independent value must be supplied, False not necessary
- When a list of GIDs is supplied the var requirment is True and
all group members without a '-' prefix must have asigned values.
A GID prefixed with a '-' indicates an exclusionary var meaning if
if provided with a current var an error will occur (think xor)
VALUE serves as default value and/or type cast reference for final value
for all variables that are int, strings, bools or float.
- When a list is provided it serves as a choice selection
where the provided value must match one listed in the list.
HELP a short descriptive line that is returned along with an error message
if an error is discovered related to the var. Also used to construct
--help/-h usage output
if all opts/args are received without error the config portion of of the ARGS dict
is overwritten with the user supplied value cast to the type of the supplied 'VALUE'
from the orig config.
opts/args supplied by the user that are not configured are ignored.
a list of mock debug values can be supplied (see SA below) for debugging providing
this list overrides reading sys.argv[1:]
#####################################################################################################
"""
import sys, os, string
class PyOptsException(Exception):
def __init__(self, value):
self.parameter = value
def __str__(self):
return repr(self.parameter)
class PyOpts(PyOptsException):
def __init__(self):
self.SA = None
self.about = ''
self.uhead = ''
self.ExitOnErr = False
self.Quiet = False
self.help = False
self.usage = []
self.Temp = []
self.Lost = {}
self.Groups = {}
self.OUT = {}
self.Found = []
self.Minimum = 0
self.Configs = ['About','Quiet','ExitOnErr','Minimum','Missing']
self.ErrorMsgs = ['Missing Member: %s of Option Group %s',
'Invalid Arguement: %s For Option %s Valid Args Are: %s',
'Duplicate Long Name Found Check Key Name In Init Dict',
'No Members Assigned To Required Group: ',
'Error Missing Required Parameter : %s %s',
'%s Options/Args Less Than Required Minimum %s',
'Exclusion Error Option %s Cannot Not Be Used With %s' ]
def OnErr(self, ErrorNum, args):
if not self.Quiet:
print self.ErrorMsgs[ErrorNum] % args
if self.ExitOnErr:
sys.exit(1)
return False
def SL(self, v, z):
d = self.Temp
if z+v in d:
if z == '-':
short = (z+[x for x in string.letters if not z+x in d][0],
z+v.upper())[not z+v.upper() in d]
self.Temp.append(short)
return short
raise PyOptsException(self.ErrorMsgs[2])
long = z+v
self.Temp.append(long)
return long
def CastAs(self, var, varType):
try:
if isinstance(varType, bool): return bool(var)
elif isinstance(varType, str): return str(var)
elif isinstance(varType, int): return int(var)
elif isinstance(varType, float):return float(var)
elif isinstance(varType, long): return long(var)
elif isinstance(varType, int): return int(var)
except:
return False
def GetValue(self, opt,cV,aV):
val = self.CastAs(aV, cV)
if not isinstance(cV, list):
return val
for x in cV:
y = self.GetValue(opt,x, aV)
if repr(y) == repr(x):
return y
choices = '|'.join([str(x) for x in cV])
self.OnErr(1,(repr(aV),opt,choices))
def LookUp(self, d, key):
for k,v in d.iteritems():
if k in self.Configs: continue
if k == key:
return v
elif isinstance(d[k], dict):
r = self.LookUp(d[k], key)
if r: return r
return None
def DependencyCheck(self, Opts):
for gid, members in self.Groups.iteritems():
missing = [x for x in members if x not in self.Found]
self.Groups[gid]['Missing'] = missing
for opt, conf in Opts.iteritems():
if opt in self.Configs:
continue
exclude = False
if isinstance(conf['REQ'], list):
for gid in conf['REQ']:
if isinstance(gid, int):
if gid < 0:
exclude=True
gid = abs(gid)
else:
if gid[0] == '-':
exclude=True
gid = gid.replace('-','')
gid = repr(gid)
if self.Groups.has_key(gid):
groupOpts = repr([x for x in self.Groups[gid].itervalues() if x != []])
groupOpts = groupOpts.replace("'", "")
if self.Groups[gid] and exclude:
opt = repr(self.LookUp(self.Groups, opt)).replace("'","")
self.OnErr(6, (opt,groupOpts))
if self.Groups[gid]['Missing'] != []:
mia = ''
for member in self.Groups[gid]['Missing']:
mia += repr(self.Groups[gid][member]).replace("'","")
return mia,groupOpts
else:
print self.Groups
raise PyOptsException(self.ErrorMsgs[3]+gid)
return False
def OP(self, Opts, SA=False):
SA = (SA,sys.argv[1:])[SA==False]
self.about = Opts.get('About', '')
self.ExitOnErr = Opts.get('ExitOnErr', True)
self.Quiet = Opts.get('Quiet', False)
self.Minimum = Opts.get('Minimum', 0)
for opt, conf in Opts.iteritems():
if opt in self.Configs:
continue
conf['GID'] = gid = conf.get('GID', None)
conf['REQ'] = req = conf.get('REQ', False)
conf['HELP'] = help = conf.get('HELP', '---')
conf['VALUE'] = value = conf.get('VALUE', '')
conf['VALUE'] = value = (value,'True/False')[isinstance(value,bool)]
short, long = (self.SL(opt[:1],'-'), self.SL(opt,'--'))
self.usage.extend([' '+short+' '*2,long+' '*(15-len(long)),
str(value)+' '*(20-len(str(value))),help,'\n'])
if gid != None:
gid = repr(gid)
if not self.Groups.has_key(gid):
self.Groups[gid]={}
self.Groups[gid][opt] = [short,long]
if not short in SA and not long in SA and req:
if gid:
self.Lost[gid] = opt
if req == True:
self.OnErr(4,(opt,help))
for x in range(len(SA)):
if SA[x] == '-h' or SA[x] == '--help':
self.help = True
continue
if SA[x] == long or SA[x] == short:
self.OUT[opt] = self.GetValue(opt, value, SA[x+1])
self.Found.append(opt)
if len(self.Found) < self.Minimum:
self.OnErr(5, (len(self.Found),self.Minimum))
mia = self.DependencyCheck(Opts)
if mia:
self.OnErr(0,mia)
if self.help:
print self.about+self.uhead+'\n'+''.join(self.usage)
sys.exit(1)
return self.OUT
#------------------------------------------------------------------------------#
# DEMO PROJECT STARTS HERE
from PyOpts import PyOpts
__author__ = "AJ Mayorga"
__version__ = "1.0.1"
__status__ = "Demo"
ABOUT="""
################################################################################
project: myOpts.py
version : """+__version__+"""
author : """+__author__+"""
status : """+__status__+"""
This is a Demo Program To Illustrate Handling Of Options/Arguments
At The Commandline
################################################################################
"""
#For Debugging Play With These To Override sys.argv[1:] to see how things are handled
SA = ['myOpts.py','--to','Mary','--fromname','boomers',
'--body','blah','--fromaddress', 'Billy@yuckbutt.com',
'--subject', 'Scooters', '--threads',43, '--template','Monkey','-h']
class OPTIONS_DEMO:
def __init__(self):
#Simple Option/Args
self.ARGS = {}
self.ARGS['About'] = ABOUT
self.ARGS['Minimum'] = 4
self.ARGS['to'] = {'VALUE': "", 'HELP':"Email List or Single Address"}
self.ARGS['fromaddress'] = {'VALUE': "", 'HELP':"Email Address of Sender e.g.WB@blah.com"}
self.ARGS['subject'] = {'VALUE': "", 'HELP':"Subject of Email"}
self.ARGS['body'] = {'VALUE': "", 'HELP':"Body/Content of Email (File or String)"}
"""
#Advanced Option/Args
PROTOS = ["HTTP","HTTPS","FTP"]
self.ARGS = {}
self.ARGS['About'] = ABOUT
self.ARGS['ExitOnErr'] = True
self.ARGS['Quiet'] = False
self.ARGS['Minimum'] = 0
self.ARGS['newtemplate'] = {'GID':0, 'REQ':[-1], 'VALUE': False, 'HELP':"Save Resulting Email As New Template"}
self.ARGS['template'] = {'GID':1, 'REQ':[-0], 'VALUE': False, 'HELP':"Email Template To Use"}
self.ARGS['to'] = {'GID':2, 'REQ':True, 'VALUE': "", 'HELP':"Email List or Single Address"}
self.ARGS['fromname'] = {'GID':3, 'REQ':[2], 'VALUE': "", 'HELP':"Name of Sender e.g. Will J Buck CEO"}
self.ARGS['fromaddress'] = {'GID':4, 'REQ':[3], 'VALUE': "", 'HELP':"Email Address of Sender e.g. WB@blah.com"}
self.ARGS['subject'] = {'GID':5, 'REQ':[4], 'VALUE': "", 'HELP':"Subject of Email"}
self.ARGS['body'] = {'GID':6, 'REQ':[5], 'VALUE': "", 'HELP':"Body/Content of Email (File or String)"}
self.ARGS['attachments'] = { 'REQ':False, 'VALUE': "", 'HELP':"Comma Separated List of Attachment Files"}
self.ARGS['threads'] = { 'REQ':False, 'VALUE': 1, 'HELP':"Number of Sending Threads"}
self.ARGS['signed'] = { 'REQ':False, 'VALUE': False, 'HELP':"Digitally Sign On Each Sent Email"}
self.ARGS['readreceipt'] = { 'REQ':False, 'VALUE': False, 'HELP':"Require Read Receipts"}
self.ARGS['linkprotocol'] = { 'REQ':False, 'VALUE': PROTOS,'HELP':"Format Embedded Links To Protocol"}
"""
self.ARGS = PyOpts().OP(self.ARGS,SA)
print self.ARGS
if __name__ == '__main__':
OD = OPTIONS_DEMO()
Diff to Previous Revision
--- revision 4 2010-06-03 19:11:16
+++ revision 5 2010-06-03 19:16:43
@@ -1,3 +1,80 @@
+"""
+PyOpts.py
+Author: AJ Mayorga
+
+A highlevel quick wrapper for simplifying commandline options/arg handling
+
+FEATURES:
+
+ - Generates shorts, longs and help/usage automatically
+
+ - Allows for specification of required options/args or groups there of
+ in addition to exclusionary opt/args or groups.
+
+ - Configures default values and selects/"choices"
+
+ - Returns a simple dictionary with key of supplied key name and value of configured type
+
+
+DETAILS AND SUCH:
+
+ By passing a dict of args that are normally present & you will use in your code anyway.
+ The arg dict is given a key name & initialize each with its own config dict consisting of
+ the following keys and values.
+
+ PROJECT KEYS:
+
+ About is an about section that will be used as a header for
+ the generated usage called by -h/--help
+
+ ExitOnErr if True when and error or exception is found in processing the opt/args
+ an error message will be generated (if Quiet=False) followed by sys.exit()
+
+ Quiet toggles error/exception message output
+
+ Minimum the minimum number of required opt/args. This is for trivial commandline
+ requirements. 0 indicates no min required.
+
+
+ All other provided keys are considered option keys the provided names for which will be used
+ to derive shorts '-p' and longs '--port'. Each option key's value is initialized with a
+ configuration dict.
+
+ CONFIG DICT:
+
+ GID group identifier for a vars used by REQ Can be alpha/num value
+
+ REQ indicates variable requirement when not present False is default
+ - True indicates an independent value must be supplied, False not necessary
+ - When a list of GIDs is supplied the var requirment is True and
+ all group members without a '-' prefix must have asigned values.
+ A GID prefixed with a '-' indicates an exclusionary var meaning if
+ if provided with a current var an error will occur (think xor)
+
+ VALUE serves as default value and/or type cast reference for final value
+ for all variables that are int, strings, bools or float.
+ - When a list is provided it serves as a choice selection
+ where the provided value must match one listed in the list.
+
+ HELP a short descriptive line that is returned along with an error message
+ if an error is discovered related to the var. Also used to construct
+ --help/-h usage output
+
+ if all opts/args are received without error the config portion of of the ARGS dict
+ is overwritten with the user supplied value cast to the type of the supplied 'VALUE'
+ from the orig config.
+
+ opts/args supplied by the user that are not configured are ignored.
+
+ a list of mock debug values can be supplied (see SA below) for debugging providing
+ this list overrides reading sys.argv[1:]
+
+
+#####################################################################################################
+"""
+
+
+
import sys, os, string
class PyOptsException(Exception):
@@ -180,6 +257,9 @@
#------------------------------------------------------------------------------#
# DEMO PROJECT STARTS HERE
+from PyOpts import PyOpts
+
+
__author__ = "AJ Mayorga"
__version__ = "1.0.1"
__status__ = "Demo"