2020-08-22
Some bits on making Python's argparse module work like Unix usually does
I recently discovered that argparse allows you to abbreviate long
options, and then Chris Wellons wrote
about Conventions for (Unix) Command Line Options, which included a criticism
of argparse
. I'm
not going to write about how to make argparse behave today, because I
haven't explored that in full; instead, this is some quick notes from
the documentation and my past experiences.
First, both Wellons and I had a bad reaction to argparse accepting abbreviated options. However, based on the documentation you probably have to accept it, because of an important postscript note:
Changed in version 3.8: In previous versions,
allow_abbrev
[beingFalse
] also disabled grouping of short flags such as-vv
to mean-v -v
.
Almost no one has Python 3.8, which means that the cure here is worse than the disease. Not accepting grouped short flags is much worse than accepting abbreviated long flags, so until Python 3.8+ is pervasive we're stuck with the latter.
As it implicitly documents (in the form of its example), argparse
allows the non-traditional style of options being intermixed with
non-option arguments on the command line, instead of requiring all
options to be before non-options. There is no way to control this.
Argparse does accept '--
' to terminate the option list (with some
caveats), after which things that look like options are non-option
arguments.
In general, using the nargs
argument
for add_argument()
is neither necessary nor useful for options (and has issues when
used with non-options). Setting
things like 'type=str
' or 'action="append"
causes the argument
parser to do the right thing; similarly, it does the right thing
when the action doesn't consume any argument value (this behavior
is documented in a postscript of the nargs
section). As Wellons
noted, argparse can fall down badly if you attempt to create an
option that takes an optional value. Fortunately, I don't think
you should do that and should stick
to options either always taking a value or never doing so. Argparse's
own examples use 'nargs="?"
' for non-options arguments that are
in fact optional.
Argparse makes a weird attempt to handle command line arguments that are negative numbers, as documented in Arguments containing -. This isn't how traditional Unix commands behave with such arguments, where a leading '-' is a leading '-' no matter what, with no attempts to guess at what should happen. This behavior is not currently optional and I don't think there's a really good way to trick argparse into not doing it.
(Actually reading much of the argparse
documentation has
already taught me useful things I didn't know, such as how the
dest
argument is optional. I'm not sure I'd want to ever leave it out,
though; explicit is better than implicit, and using 'dest
' leaves
a visible reminder in the code of what attribute holds the result.)