00001 """
00002
00003 For parsing commandline values
00004 into a dictionary
00005
00006 """
00007
00008 __copyright__ = """
00009 Copyright 2008 Sean Ross-Ross
00010 """
00011 __license__ = """
00012 This file is part of SLIMpy .
00013
00014 SLIMpy is free software: you can redistribute it and/or modify
00015 it under the terms of the GNU Lesser General Public License as published by
00016 the Free Software Foundation, either version 3 of the License, or
00017 (at your option) any later version.
00018
00019 SLIMpy is distributed in the hope that it will be useful,
00020 but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00022 GNU Lesser General Public License for more details.
00023
00024 You should have received a copy of the GNU Lesser General Public License
00025 along with SLIMpy . If not, see <http://www.gnu.org/licenses/>.
00026 """
00027
00028
00029 from slimpy_base.Environment.InstanceManager import InstanceManager
00030 from optparse import OptionParser, OptionGroup
00031 from sys import argv, modules
00032 from slimpy_base.setup.default_options import options
00033
00034
00035 def make_version( ):
00036 '''
00037 return a nicely formatted version string
00038 '''
00039 import slimpy_base
00040 main = modules["__main__"]
00041
00042 lines = []
00043 push = lines.append
00044 if hasattr( main, "__version__" ):
00045 push( main.__version__ )
00046 push( slimpy_base.__version__ )
00047 push( slimpy_base.__license__ )
00048
00049 return "\n".join(lines)
00050
00051 class SlimOptionParser( OptionParser ):
00052 """
00053 a subclass for optparse.OptionParser
00054 """
00055
00056 def __init__( self ,*arg, **kw):
00057 '''
00058
00059 '''
00060 new_kw = dict( version=make_version() )
00061 new_kw.update(kw)
00062
00063 OptionParser.__init__(self, *arg, **new_kw )
00064
00065 self._required = set()
00066
00067 self._types = {}
00068 self._defaults = {}
00069 self._prog_args = []
00070
00071 self.env = InstanceManager()
00072
00073 self.add_all_slim_options( )
00074
00075 from slimpy_base.setup.DEFAULTS import DEFAULTS
00076
00077 self.set_defaults( **DEFAULTS )
00078
00079 def Types(self, *E, **kw):
00080 '''
00081 set the type for a prameter
00082 parse retuns values from type as Type[key]
00083 '''
00084
00085 self._types = dict(*E, **kw)
00086
00087 def Parameters(self, *args):
00088 """
00089 set parameters for
00090 """
00091 self._prog_args = list(args)
00092
00093 def Defaults(self, *E, **kw):
00094 self._defaults = dict( *E, **kw )
00095
00096 def new_group(self, title, doc, *opts):
00097 '''
00098 add a group of title and with 'doc' to the parser
00099 @param title:
00100 @type title: str
00101 @param doc:
00102 @type doc: str
00103 '''
00104 title += ":\n " + "="*len(title)
00105 group = OptionGroup(self, title, doc)
00106 for opt in opts:
00107 group.add_option( options[opt] )
00108 self.add_option_group( group )
00109
00110 return
00111
00112 def add_the_rest(self):
00113 """
00114 add any options that are not in a group
00115 """
00116 for option in options.values():
00117 opt_str = option.get_opt_string()
00118 if self.has_option(opt_str):
00119 pass
00120 else:
00121 self.add_option( option )
00122
00123 def _getit(self, par):
00124 'helper function'
00125 ret = self._defaults.get( par, self._types.get(par,'X') )
00126 return par, hasattr(ret, "__name__") and "'%s'"%ret.__name__ or ret
00127
00128 def _set_usage( self ):
00129 '''
00130 sets usage parameter of parser with data
00131 collected from the '__main__' module
00132 '''
00133 maintmp = modules['__main__']
00134
00135 if self._prog_args:
00136 strs = [ "%s=%s" %self._getit(par) for par in self._prog_args ]
00137 opstr =", ".join( strs )
00138 usage="python %%prog [ options ] [ %(opstr)s ]" %vars()
00139
00140
00141
00142 elif hasattr( maintmp, 'usage' ):
00143 usage = maintmp.usage
00144
00145 else:
00146 usage = "python %prog [slim options] [program options]"
00147
00148 if maintmp.__doc__:
00149 spacer = '\n' + "-"*(len(usage)+10)
00150 usage+=spacer+"\n"+maintmp.__doc__.strip("\n ")+spacer
00151
00152 OptionParser.set_usage(self, usage)
00153
00154 def add_all_slim_options(self):
00155 '''
00156 add options from default_options module
00157 '''
00158
00159 self.new_group("MPI Utilities", "mpi related functions",
00160 "mpi","no_mpi","mpi_run","mpi_flags",
00161 )
00162
00163 self.new_group('Distributed',"helper funcs for '--dist' option "
00164 "(see Runners)",
00165 'eps','nwin')
00166
00167 self.new_group('Data-path', "direct data flow",
00168 'localtmpdir', 'globaltmpdir')
00169
00170 self.new_group( "Output", "control the output" ,
00171 'verbose', 'quiet' ,'log','debug')
00172
00173 self.new_group("Runners",
00174 "runners determine what SLIMpy does with the comands and data",
00175 'scons','dot','dottest','dryrun','multicore' ,'test' ,'dist')
00176
00177 self.new_group("Sanity Checks", "Determines how much checking is done at 'compile time'",
00178 'check_paths','strict_check','no_check_paths','walltime')
00179
00180 self.add_the_rest()
00181
00182
00183 def parse( self , *args):
00184 """
00185 parse all slimpy options into global vars and return
00186 a list of all commandlist parameters not used in the option
00187 parse.
00188 """
00189 log = self.env['record'](1, 'stat' )
00190
00191 print >> log, "SLIMpy: Building AST ..."
00192
00193 self.set_defaults( runtype='normal' )
00194
00195 self._set_usage()
00196
00197
00198 opts , args = self.parse_args( *args )
00199
00200 ib = lambda b: int(bool(b))
00201 tot = ib(opts.jobs) + ib(opts.mpi) + ib(opts.mpi)
00202
00203 if tot > 1:
00204 self.error( "options -j/--jobs, --mpi and --dist "
00205 "are mutualy excusive\n"
00206 "please choose only one option\n" )
00207
00208 globcpar = opts.__dict__
00209
00210 self.env['slimvars'].setglobal( **globcpar )
00211
00212
00213 cpar = self.clp( *args )
00214
00215 self._check_required( cpar)
00216
00217 cpar_and_defaults = self.set_types(cpar)
00218
00219 return cpar_and_defaults
00220
00221 def set_types(self, cpar):
00222 '''
00223 convers the string values in cpar to the
00224 corresponding type in self._types
00225
00226 retuns defaults updated with new typed cpar
00227 '''
00228 if self._types:
00229 for atype in self._types:
00230 if cpar.has_key(atype):
00231 try:
00232 cpar[atype] = self._types[atype]( cpar[atype] )
00233
00234 except Exception, exc:
00235 type_name = self._types[atype].__name__
00236 value = cpar[atype]
00237 exc_type = exc.__class__
00238 msg=( "could not convert arg '%(atype)s' with value '%(value)s' to type '%(type_name)s'\n"
00239 "got - %(exc_type)s: %(exc)s" %vars() )
00240 self.error( msg )
00241
00242 _defaults = dict(self._defaults)
00243
00244 _defaults.update( cpar )
00245
00246 return _defaults
00247
00248 def check_required( self, *args ):
00249 '''
00250 add parameter to be checked when parse args is called
00251 if more that one arg then will check that only
00252 one of the arguments from args exists
00253 '''
00254 if len(args) == 1:
00255 arg = args[0]
00256 self._required.add( arg)
00257 elif len(args) > 1:
00258 self._required.add( args )
00259
00260 return
00261
00262 def _check_required(self, pars):
00263 '''
00264 raise an exception if a key specified in
00265 pars is not in pars
00266
00267 @param pars:
00268 @type pars: dict
00269 '''
00270
00271 for par in self._required:
00272 if isinstance(par, tuple):
00273 pars_set = set( pars )
00274 par_set = set( par )
00275 if len(pars_set.intersection(par_set)) < 1:
00276 opstr ="= | ".join( par )+"="
00277 self.error("at least one of [ %(opstr)s ] "
00278 "parameters must be supplied\n" %vars())
00279
00280 elif par not in pars:
00281 self.error("parameter '%s=' not supplied\n" %par)
00282
00283 def clp( self, *arg ):
00284 """
00285 parse the comand line *args is a list of keys as of file
00286 """
00287 if len( arg ) is 0:
00288 arg = argv
00289 par = {}
00290 for i in range( 0, len( arg ) ):
00291
00292 spl = arg[i].split( "=" )
00293 if len( spl ) is 2:
00294 if spl[1] is 'None':
00295 par[spl[0]] = None
00296 else:
00297 par[spl[0]] = spl[1]
00298 return par
00299
00300
00301
00302