Comparing Option-Parsing Libraries

NOTE: this page is present for historical purposes only. The getopt-sig is retired, and Optik was added to the Python standard library (as optparse) in Python 2.3. (It was checked in to Python's CVS tree in November 2002, and first released in July 2003.)

Since I proposed Optik for the Python standard library, a number of other option-parsing libraries have come to light. I'm trying to evaluate them by implementing the same real-world command-line interface with several different libraries. Currently, implementations exist for:

  • Greg Ward's (that's me) Optik
  • Russ Cox' iterator interface (ArgParser)
  • Albert Hofkamp's argtools (page no longer available)
  • David Boddie's CMDSyntax (page no longer available)

User interface

The interface I have chosen to implement is that of my ripoff CD-ripping script. The main features of this interface are:

  • straightforward, standard interface (no complicated interactions between options)
  • a respectable number (around 17) of options -- enough that some sort of high-level command-line parsing help is really nice to have, but not so many that it would take me forever to reimplent the interface several times
  • a fair variety of option types and actions (to use Optik's terminology) (but nothing really arcane or unusual)
  • no positional arguments are expected or allowed -- ie. everything Ripoff needs to know can be taken from command-line options.

To keep things concrete, here is Ripoff's help text (as generated by Optik).

One weakness of Ripoff's command-line interface is that several flag options don't have a negative counterpart: eg. there is a --keep-tmp option, but no --no-keep-tmp. That sort of thing really is necessary in the real world, where a program's default (no-keep-tmp in this case) might be overridden by a config file, and then overridden again on the command-line. This weakness is currently reflected in all three of my test re-implementations.

Internal interfaces

Internally, Ripoff works by passing around a single object that contains all the values from the command-line. E.g., the user-selected verbosity level is in options.verbose, and the CD-ROM device file is in options.device. There are not quite as many option values as there are options: the -v/--verbose option and -q/--quiet both update options.verbose, and -p/--use-pipes and -f/--use-files both update the options.use_pipes flag.

I have preserved this in all of my test re-implementations. This works to Optik's benefit (since it already puts option values in a dedicated object); doesn't have much affect on the iterator version (it just means a bit more typing); and it makes argtools look bad, since I have to explicitly copy all of my option values from the parser object to my dedicated option values object.

And now, ladies and gentlemen...

Enough delay, on with the show! First, some simple statistics about the three re-implementations:
library total code[1] code (no help)[2]
Optik 6234
  1. as reported by Dinu Gherman's pycount -- ie. this is lines of real code, not counting blanks, comments, or docstrings (but counting literal strings, such as help and usage text)
  2. ie. with all explicit help text removed. For ArgParser and argtools, this is just a big literal string, since these libraries don't do automatic help generation. For Optik, this just means removing the help parameter from each option; even removing this per-option help text, Optik still provides a --help option that reports which options are available

But as Mark Twain said: there are lies, damned lies, and statistics. So let's see some code.

  • is Ripoff's command line interface implemented with Optik (snipped right out of the Ripoff source code, of course)
  • is the re-implementation using Russ Cox' iterator interface
  • is the re-implementation using Albert Hofkamp's argtools
  • the example code for CMDSyntax, provided by David Boddie (page no longer available)

If you actually want to run any of these without modifying them, you'll need to get the Ripoff source code from its CVS repository. This is because I wanted 1) a realistic --version option (which uses ripoff.__version__), and 2) realistic help for the -d/--device option (which relies on the ripoff.cdrom extension module, specifically the get_default_device() function). The real purpose here, though, is to examine the code, not to run it.