[getopt-sig] Comparing option libraries

Greg Ward gward@python.net
Mon, 25 Feb 2002 18:02:59 -0500


On 25 February 2002, Russ Cox said:
> Have you significantly changed the Optik library
> since this discussion started?

The main changes are that you can now often get away without explicitly
supplying a 'dest', and 'type' defaults to "string".  This definitely
reduces the noise level, and cost about 3 lines of code to add.

> If I'd seen something
> like http://optik.sourceforge.net/ripoff_optik.py
> instead of the example at http://optik.sourceforge.net/,
> I wouldn't have made such a big deal about the iterator.

And if you hadn't made such a big deal about the iterator, I wouldn't
have been driven to make these improvements in Optik.  So obviously it
was all part of my master plan to force myself into improving Optik just
a little bit more.  ;-)

> What if Optik defined two subclasses, one that takes
> no arguments and one that takes one argument?

Hmmmm.  I presume you're referring to Optflag and Optarg:

> 	Optarg("-b", "--output-base", var="DIR",
> 		help="base output directory"),
> 	Optarg("-t", "--tracks", 
> 		help="tracks to rip (default: all) (example: 1,2-5,8)"),
> 	Optflag("-p", "--use-pipes", "--synchronous",
> 		help="use named pipes for intermediate output "
> 			"(uses less temporary disk space, works great "
> 			"if encoding is faster than ripping) [default]"),

First, I think I would call those two classes FlagOption and
ValueOption, which is a bit more verbose, but a bit more verbose.
(>wink<).  And I would add add_flag_option() and add_value_option() to
OptionParser, since I still like having two ways to populate the option
list (even if that violates Python's Prime Directive).

Second, my now-standard response to anyone proposing a new feature for
Optik is this: implement it yourself and show me where Optik needs
refactoring.  Usually the challenge goes unanswered, and I end up doing
it myself, which is just as good.  Maybe better, because then I have a
good understanding of how it needs to be refactored.  Anyways, you have
my blessing, nay encouragement, to implement these subclasses (including
an OptionParser with add_{flag,value}_option()) and to howl loudly if
some part of Optik needs refactoring to support them.

> And why not make type a real type instead of a string?

I think what you want is to be able to say (eg.)

   add_option("-f", type=int, ...)

instead of 

   add_option("-f", type="int", ...)

-- correct?  So what you're really asking for is that Optik type's be
specified by identifiers, not by strings.  There happen to be convenient
built-in identifiers for the three types Optik supports by default.  But
if you want to define a type for, say, "readable file", then you also
have to supply an identifier to represent that type.  My guess is you'll
create a global string variable somewhere and users of your new type
will just have to import that variable from somewhere, which is slightly
*less* convenient than using a string.  But it is also slightly less
error-prone than supplying a string, since Python itself will tell you
you've typed 'fiel' instead of 'file', whereas currently only Optik
tells you this.  Hmmm.

Tell you what: I think I'll make Optik recognize the str, int, and float
builtins as synonyms for "string", "int", and "float".  Then if you
write your own Option subclass that adds new types, you can specify
those types however you like.

> Further, what if the action string could be something
> to eval instead of needing to be a canned action string?

Hmmmm.  I'm not keen on overloading "action" to mean "one of these
canned actions, OR some bit of code to eval" -- makes it tricky to know
what to do if someone mistypes an action string.

Two alternatives:

  * add another Option attribute (and kw arg to Option.__init__() and
    OptionParser.add_option()) where you specify a bit of code to
    eval, eg.

      Optflag("-v", eval="verbose += 1",
              help="increase verbosity level")

    Supplying this would implicitly set 'action' to "eval" (a new canned
    action).

  * overload the callback mechanism, so you can supply a bit of code
    to evaluate instead of a function.

I prefer the former -- I think actions should do one thing and do them
well, and I'm not shy about adding new actions.
          
> Finally, there should be some similar way to specify how to parse the
> rest of the command line; otherwise you're encouraging people
> to use options when they're not really necessary, because
> they get the nice benefits of things like type checking.

I've always thought that the only thing to be done with positional args
is make sure there are the right number of them, eg. you supply a pair
(n, m) and Optik makes sure that n <= len(args) <= m.  But
"type-checking" positional args makes sense if there are "types" like
"readable file" or "output directory".

Hmmmm.  I'm open to interface suggestions.  Ideas, anyone?

        Greg
-- 
Greg Ward - programmer-at-big                           gward@python.net
http://starship.python.net/~gward/
Drive defensively -- buy a tank.