/search.css" rel="stylesheet" type="text/css"/> /search.js">
00001 #!/usr/bin/env python 00002 """ 00003 General purpose integration of ArgumentParser with ConfigParser 00004 00005 """ 00006 import sys, os, logging 00007 from pprint import pformat 00008 from argparse import ArgumentParser, RawDescriptionHelpFormatter 00009 from ConfigParser import RawConfigParser, NoSectionError 00010 00011 log = logging.getLogger(__name__) 00012 00013 class AParser(ArgumentParser): 00014 """ 00015 Primes an argparser with defaults read from a section of an 00016 ConfigParser style config file and sets up logging 00017 00018 Operates via 2-stage parsing 00019 00020 Usage:: 00021 00022 parser = AParser(defpath="~/.scraper.cfg",defsect="default") 00023 parser.add_argument( '-m','--maxiter', help="maximum iterations, or 0 for no limit") 00024 parser.set_defaults( maxiter=0 ) 00025 args = parser() 00026 print args 00027 00028 Draws upon: 00029 00030 * http://blog.vwelch.com/2011/04/combining-configparser-and-argparse.html 00031 * http://www.doughellmann.com/PyMOTW/argparse/ 00032 00033 """ 00034 def _read_conf(self, defpath, defsect ): 00035 """ 00036 Note drawback of this have-your-cake-and-eat-it approach that combines 00037 argparsing with ConfigParser 00038 for `--help` to work must specify an existing default config section 00039 """ 00040 pp = ArgumentParser( add_help=False) ## parent parser 00041 00042 pp.add_argument("-l","--loglevel", help="logging level INFO, DEBUG, WARN,... Default: %(default)s ") 00043 pp.add_argument("-c","--cfg", help="Path to config file. Default: %(default)s" ) 00044 pp.add_argument("-s","--sect", help="Section in config file. Default: %(default)s" ) 00045 pp.set_defaults( cfg=defpath , loglevel="INFO" , sect=defsect ) 00046 pargs, argv = pp.parse_known_args() ## unparsed args are returned 00047 00048 if pargs.loglevel: 00049 level = getattr( logging , pargs.loglevel.upper() ) 00050 logging.basicConfig(level=level ) 00051 00052 if pargs.cfg: 00053 rcp = RawConfigParser() 00054 rcp.read([os.path.expandvars(os.path.expanduser(pargs.cfg))]) 00055 sect = getattr(pargs, 'sect', "Default" ) 00056 try: 00057 conf = dict(rcp.items(sect)) 00058 except NoSectionError: 00059 log.warn("no config file at %s or no section %s " % ( pargs.cfg, sect ) ) 00060 sys.exit(1) 00061 log.info( "base config read from %s:%s " % (pargs.cfg, sect,) ) 00062 log.debug( "giving %s " % (pformat(conf)) ) 00063 00064 self.loglevel = pargs.loglevel 00065 self.pp = pp 00066 self.pvars = vars(pargs) 00067 self.argv = argv ## hold on to unparsed args for subsequent parsing 00068 self.conf = conf 00069 00070 def __init__(self, *args, **kwargs ): 00071 defpath = kwargs.pop('defpath') # mandatory 00072 defsect = kwargs.pop('defsect') # mandatory 00073 00074 00075 self._read_conf(defpath=defpath, defsect=defsect) 00076 00077 description = kwargs.pop('description', __doc__ ) 00078 00079 ArgumentParser.__init__( self, parents=[self.pp], description=description, 00080 formatter_class=RawDescriptionHelpFormatter ) # Don't mess with format of description 00081 00082 d = self.pvars 00083 d.update( self.conf ) 00084 self.set_defaults( **d ) 00085 #log.debug("ArgumentParser primed with defaults %r %r " % ( self.pvars, self.conf ) ) 00086 00087 def __call__(self, *args, **kwa ): 00088 noargs = kwa.get('noargs',False) 00089 args = [] if noargs else self.argv 00090 d = vars( self.parse_args( args ) ) 00091 return dict(d, loglevel=self.loglevel ) 00092 00093 00094 00095 if __name__ == '__main__': 00096 ap = AParser(defpath="~/.scraper.cfg",defsect="default") 00097 ap.add_argument( '-m','--maxiter', help="maximum iterations, or 0 for no limit") 00098 ap.set_defaults( maxiter=0 ) 00099 print ap() 00100