Re: Gathering unknown option data without quitting

Allan Crooks <[email protected]> Sat, 06 May 2006 21:40:08 +0100
Newsgroups gmane.comp.python.optik.user
Message-ID <[email protected]>
Greg Ward wrote:
> On 03 May 2006, Allan Crooks said:
> 
>>I would like to do something like this:
>>
>>def setup(func):
>>    configure parser
>>    options, args, unknown_options = parser.parse_args()
>>    environment.handle(options)
>>    func(environment, unknown_options)
>>
>>At the moment, you can't pass any options intended for the func
>>function, since it is rejected as an unknown option for the parser
>>created by the setup function.
>>
>>Has anyone written something to extend optik to do this?
> 
> Not me!  I added a smart-ass remark to the docs years ago to the effect
> that "if you don't like the fact that Optik terminates your process on
> error, you'll need to subclass OptionParser and override error()".  I
> think you're the first person to actually take me up on this.

Yes, I remember reading that. :)

>>I think I could
>>probably write something to get what I want, but I'm just wondering
>>whether I could reuse existing code rather than writing something myself.
> 
> On reflection, and looking at the code again, I think I would start by
> overriding _process_args() rather than error().  You want to call the
> real _process_args(), but catch BadOptionError.  (You probably want to
> let OptionValueError pass up and be handled by the "except" clause in
> parse_args().)  Then accumulate the bad options in a list somewhere.  Or
> put them in the parser's 'largs' variable, if you don't need to
> distinguish between leftover positional args and bad options.

This is what I came up with - I decided to just store the values in
largs. It seemed quite straight-forward to do actually - though it
interacted with a few too many subclass values.

--

class UnknownOptionParser(OptionParser):

  def _process_long_opt(self, rargs, values):
    option, remaining_args = rargs[0], rargs[1:]
    try:
      OptionParser._process_long_opt(self, rargs, values)
    except BadOptionError, error:
      # OptionParser may actually leave rargs in a mangled state (at the
      # time of writing) - what we will do is restore rargs.
      self.largs.append(option)
      self.rargs[:] = remaining_args

  def _process_short_opts (self, rargs, values):
    first_option = rargs[0][:2]
    if self._short_opt.get(first_option):
      # We'll assume the short options will be valid options for this
      # parser.
      OptionParser._process_short_opts(self, rargs, values)
    else:
      # We'll assume that the short options should be left unresolved.
      self.largs.append(rargs.pop(0))

--

> I thikn what's going to make this difficult is dealing with "-ffoo" or
> "--file=foo" where "foo" is the argument to -f/--file.  Good luck, and
> don't forget: Use The Source, Luke.

This code deals with handling double underscores. As for dealing short
options - that's too awkward (impossible, really). There are two
compromises I could go with.

1) We assume that we won't get several short options together like this:
-abcd (otherwise, we can't reliable distinguish between being provided a
short option with a value, or multiple short options (last one with a
value), or multiple short options (with no value)).

2) We assume we won't get a mixture of known short options and unknown
short options - which is what I've done here.

Allan.


-------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642