[getopt-sig] Option package requirements

Greg Ward gward@python.net
Sun, 24 Feb 2002 16:55:50 -0500


On 24 February 2002, Matthias Urlichs said:
> - Modules should be able to add their own options without requiring
>   modification of the main program (so there should be a single default
>   option-parser object which is instanciated only once).
> 
> - Options and help strings should be declared ONCE, in ONE place.
>   If that means extra work for the option parser when it has to actually
>   display the help text, so be it.

I'm +1 on both of those, in case there was any doubt.  ;-)

> IMHO it's of no use at all to specify an option processing package which
> ends up being unable to handle real-world requirements. Real programs have
> a whole bunch of usages, and I want my Python program to be able to
> emulate those other programs.

I'm strongly opposed to further complicating Optik in order to support
esoteric needs and downright bad UI design.  My goal right now is to
keep refactoring Optik so that esoteric needs can be met by subclassing,
and to simplify it to answer the (fair) criticisms that it's too
complex.

Regarding your specific proposals...

> - Positional vs. global options. Suppose I want to rewrite
>   sox, the command-line sound converter. It has this Usage string:
>   
>   sox [ gopts ] [ fopts ] ifile [ fopts ] ofile [ effect [ effopts ] ]
> 
>   This might boil down to an Optik call like
>   
>   parser.add_option(1, ...)
> 
>   meaning that this "option" is processed for the first non-option argument.
>   (In this case, a callback function would stash the input file's fopts
>   someplace safe so that they're not overwritten by the output file's
>   fopts.)

Positional arguments are not options.  Options are not positional
arguments.  Confusing the two will lead to a confused interface and
deeply confused users.  (As an experienced programmer with a good grasp
of command-line UI who has struggled with sox to get it to do what I
want, I can testify that at least one user is deeply confused by it.)

Anyways, you could achieve this with Optik by setting
allow_interspered_args false, and restarting argument parsing multiple
times.  Eg.

  parser1 = OptionParser(...)
  parser1.disable_interspersed_args()
  (options1, args) = parser1.parse_args()
  ifile = args.pop(0)
  parser2 = OptionParser(...)   # partially different option list this time
  parser2.disable_interspersed_args()
  (options2, args) = parser2.parse_args(args)
  ofile = args.pop(0)
  if args:
      effect = args.pop(0)
      # ... validate effect ...
      parser3 = OptionParser(...)   # completely different option list
      (options3, args) = parser3.parse_args(args)
      # ... bomb if any args left ...

It's not terribly pretty, but it should work.

> - A way to end option processing / gobble up all remaining arguments.
> 
>   Suppose I want to rewrite ssh. It haas this option:
> 
>   ssh HOST foo ...
> 
>   which calls the remote "foo" program with any options given afterwards.
>   (Enclosing these options in a string, like "sh -c" wants me to, is NOT
>   the Right Way.)

Again, you can do this with Optik now by setting
enable_interspersed_args false.  Optik will stop parsing when it hits
the HOST argument, and then you can do what you wish with the remaining
arguments.

> - Freely mix options and arguments.

Optik already handles this by default, but you can turn it off when you
need to (see above).

> - Shorthand arguments.

Optik already handles this.  If for some perverse reason you do *not*
want option abbreviation (eg. you hate your users and you want them to
suffer), you'll be able to disable it in Optik 1.3 by overriding one
method of OptionParser.

> - Optional option arguments.
> 
>   Suppose I want to rewrite the GCC front-end. See, for example, its "-g"
>   and "-O" options.
> 
>   gcc file       -- no -O given
>   gcc -O file    -- -O without value
>   gcc -O1 file   -- -O with value
>   gcc -O 1 file  -- process the two files "1" and "file".

Yet another argument for optional option arguments.  I'm glad we're all
using the same awkward terminology for this concept now, because it *is*
awkward.  Currently not supported directly by Optik, but you should be
able to pull it off with a callback.  I'm going to try to implement it
through subclassing to see if I can refactor that code to be more
friendly, but I'm skeptical it will work.  I think this case is rare
enough that just saying, "Use a callback" is good enough.  (Especially
if there's a canonical implementation in the examples/ directory.)

        Greg
-- 
Greg Ward - programmer-at-large                         gward@python.net
http://starship.python.net/~gward/
Quick!!  Act as if nothing has happened!