Comparing Option-Parsing Libraries
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 | 62 | 34 |
iterator | 112 | 73 |
argtools | 108 | 69 |
- 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)
- 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.
- ripoff_optik.py is Ripoff's command line interface implemented with Optik (snipped right out of the Ripoff source code, of course)
- ripoff_iterator.py is the re-implementation using Russ Cox' iterator interface
- ripoff_argtools.py 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.