Re: partial option parsing

Francisco Borges <[email protected]> Mon, 19 Dec 2005 20:01:26 +0100
Newsgroups gmane.comp.python.optik.user
Organization Alfa Informatica - Rijksuniversiteit Groningen
Message-ID <[email protected]>
Hello,

Sorry it took so long to answer, other things kept stopping me.

=BB On Fri, Dec 09, 2005 at 09:19PM -0500, David Goodger wrote:

> [Francisco Borges]
> > CASE 1:
> >
> > Turning "on" certain groups of options though some action swicht:
> >
> > $ wiel train --train-specific-option
>
> Look in the list archives for "partial option parsing" (there are 2
> threads).  These directly apply to this issue.

Thank you for the pointers!! But as I haven't found any code there, here
is my own ;-)

I've subclassed OptionGroup and OptionParser to allow the use of partial
"switched" options.

The idea is:

- If group has 'switch', options are not added to the parser but stored

- If there are groups with switches and switch is in cmdline:
- add options from target group,
- continue parsing.

- only one switch can be made active, a second is considered a normal
argument.

Known Bugs: Lacking decent help messages.

   -----------

Any comments on the code?

Cheers,
Francisco.

#-----------------------------------------------------------------------
#! /usr/bin/env python
# -*- coding:iso-8859-15 -*-
#    Time-stamp: <switch.py 19dec05 19hrs 44min borges>
# $Id: switch.py 975 2005-12-19 18:50:34Z borges $
#-----------------------------------------------------------------------
"""
Group Switches for Optik.
"""
__author__ =3D 'Francisco D. Borges <[email protected]>'
__date__ =3D "$Date: 2005-12-19 19:50:34 +0100 (ma, 19 dec 2005) $"
__revision__ =3D "$Revision: 975 $"

import logging
logging.basicConfig(format=3D'%(levelname)-8s %(message)s')
log =3D logging.getLogger()
log.setLevel(5)

import optparse

class SW_OptionGroup(optparse.OptionGroup):

    def __init__(self, parser, title, description=3DNone, switch=3DNone):
        self.switch =3D switch
        self._stored_options =3D []
        optparse.OptionGroup.__init__(self, parser, title, description)

    def add_option(self, *args, **kwargs):
        if not self.switch:
            return optparse.OptionGroup.add_option(self, *args, **kwargs)
        self._stored_options.append([args, kwargs])

    def activate_opts(self):
        log.debug("activating options of '%s'" % self.switch)
        for iargs, ikwargs in self._stored_options:
            optparse.OptionGroup.add_option(self, *iargs, **ikwargs)

OptionGroup =3D SW_OptionGroup

class SW_OptionParser(optparse.OptionParser):

    def parse_args(self, args=3DNone, values=3DNone):
        switches =3D [ g.switch for g in self.option_groups if g.switch ]
        if not switches:
            log.debug("No switches!")
            return optparse.OptionParser.parse_args(self, args, values)
        elif len(switches) !=3D len(set(switches)):
            log.error(" ".join(switches))
            raise StandardError
        return self.parse_switch(args, values, switches)

    def parse_switch(self, args, values, switches):
        """Parse command line activating switched options if switch is fo=
und.

Some observations:
- all groups with switches are OFF untill switch is seen;
- there can be only one switch per command line.
- if interspersed_args was disable, things might not work (for you :-P).
"""
        if self.allow_interspersed_args:
            old_interspersed =3D True
            self.disable_interspersed_args()
        else:
            old_interspersed =3D False

        opt, new_values =3D optparse.OptionParser.parse_args(self, args, =
values)

        if not new_values:
            return opt, new_values

        if new_values[0] not in switches:
            log.debug("No valid switches found!")
            if not old_interspersed: # XXX A horrible "if 'not True'"
                return opt, new_values
        else:
            log.debug("Switch is ON")
            switch =3D new_values.pop(0)
            for group in self.option_groups:
                if group.switch =3D=3D switch:
                    group.activate_opts()
                    break

        if old_interspersed:
            self.enable_interspersed_args()

        opt2, values2 =3D optparse.OptionParser.parse_args(self, new_valu=
es, values)

        # Re-set changed values and add new options:
        for k, v in self.defaults.iteritems():
            curval =3D getattr(opt2, k, v)
            if curval !=3D v or not hasattr(opt, k):
                setattr(opt, k, curval)
        return opt, values2


if __name__ =3D=3D '__main__':
    prs =3D SW_OptionParser()
    prs0 =3D SW_OptionParser()

    # General Option...
    gopts =3D [prs0.add_option('--path', help=3D'Some path...')]

    ginp =3D OptionGroup(prs, 'Input Options', switch=3D'input')
    ginp.add_option('-m', '--model', action=3D"store", dest=3D'modelfile'=
,
                    metavar=3D'FILE', help=3D"Model to use")
    ginp.add_option('-b', '--base-line', action=3D'store_true', dest=3D'b=
aseline',
                    help=3D'Determine a baseline performance')
    ginp.add_option('--models-dir', action=3D'store', dest=3D'mdir', meta=
var=3D'DIR',
                   default=3D'.', help=3D'Directory where to find multipl=
e models.')
    ginp.add_options(gopts)

    g2 =3D OptionGroup(prs, '2G: Output', switch=3D'output')
    g2.add_option("--g2only", help=3D'Some help')
    g2.add_options(gopts)

    g3 =3D OptionGroup(prs, '3G: Always ON!')
    g3.add_option('--g3only', help=3D'more help')

    prs.add_option_group(ginp)
    prs.add_option_group(g2)
    prs.add_option_group(g3)

    (opt, args) =3D prs.parse_args()
    print opt, args



-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click