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 |
Notes:
- 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.
|