optparser question

Steven Bethard steven.bethard at gmail.com
Fri Dec 22 10:32:42 EST 2006


Michele Petrazzo wrote:
> I'm trying optparse and I see a strange (for me) behavior:
> 
> def store_value(option, opt_str, value, parser):
>     setattr(parser.values, option.dest, value)
> 
> parser = optparse.OptionParser()
> parser.add_option("-f", "--foo",
>                   action="callback", callback=store_value,
>                   type="int", dest="foo")
> 
> args = ["-f", "1"]
> (options, args) = parser.parse_args(args)
> print options, args
> 
> {'foo': 1} [] # with the type
> {'foo': None} ['1'] #without it
> 
> If I not specify the type in add_options, the value aren't passed to the
> store_value (into value variable), but it's understood as args!
> If I specify it, it
> 
> Is this normal?

I believe so.  The optparse module lists 'callback' as one of the 
TYPED_ACTIONS but not one of the ALWAYS_TYPED_ACTIONS, so it should only 
set nargs=1 if a type= argument was provided.  That means that callbacks 
will be assumed to take zero arguments until you pass an nargs= or a 
type= argument.

You can try using argparse_, which doesn't make these weird inferences, 
and generally assumes that your action will take a single argument 
unless you specify otherwise::

     >>> import argparse
     >>> class StoreValue(argparse.Action):
     ...     def __call__(self, parser, namespace, value, opt_str=None):
     ...         setattr(namespace, self.dest, value)
     ...
     >>> parser = argparse.ArgumentParser()
     >>> parser.add_argument('-f', '--foo', action=StoreValue)
     >>> parser.parse_args('-f 1'.split())
     Namespace(foo='1')

     >>> parser = argparse.ArgumentParser()
     >>> parser.add_argument('-f', '--foo', action=StoreValue, type=int)
     >>> parser.parse_args('-f 1'.split())
     Namespace(foo=1)

Not sure exactly what your callback was trying to do though -- it seems 
like you're just duplicating the 'store' action (which is the default 
anyway).

FWIW, if you want to write a custom action in argparse, you don't have 
to worry about the weird TYPED_ACTIONS kinds of things in optparse. 
Just specify in the action's constructor whatever defaults you need, e.g.::

     >>> class MyStoreValue(argparse.Action):
     ...     def __init__(self, nargs=2, type=int, **kwargs):
     ...         superinit = super(MyStoreValue, self).__init__
     ...         superinit(nargs=nargs, type=type, **kwargs)
     ...     def __call__(self, parser, namespace, value, opt_str=None):
     ...         setattr(namespace, self.dest, value)
     ...
     >>> parser = argparse.ArgumentParser()
     >>> parser.add_argument('-f', '--foo', action=MyStoreValue)
     >>> parser.parse_args('-f 1 2'.split())
     Namespace(foo=[1, 2])

Of course, you can always specify nargs= and type= in the 
``add_argument()`` call too.

.. _argparse: http://argparse.python-hosting.com/

STeVe



More information about the Python-list mailing list