Daniel Goldfarb
Daniel Goldfarb

Reputation: 7714

Python argparse optional dash-integer argument

Is it possible to add an optional argument with argparse as -<integer>,

similar to unix head and tail commands which accept -<integer> to say how many lines to print,
or similar to git log which accepts -<integer> to say how many log entries to print?

For example,

head -4     # print four lines
tail -12    # print 12 lines.
git log -7  # print 7 log entries

Whereas the argument is optional, for example these all work:

head        # print default number of lines
tail        # print default number of lines
git log     # print all log entries through system pager

Is there a general and/or accepted way to do this in Python?

Thanks.

Upvotes: 2

Views: 300

Answers (2)

hpaulj
hpaulj

Reputation: 231385

Trying to accept dash numbers as argument flags creates ambiguities. When should they be interpreted as negative numbers and when as flags? In addition argparse does not allow 'dynamic' or patterns; you have define each flag.

Normally '-2' is parsed as a value - numeric if type is int:

In [250]: p=argparse.ArgumentParser()
In [251]: p.add_argument('foo', type=int);
In [252]: p.parse_args(['-2'])
Out[252]: Namespace(foo=-2)

We can define a flag with a numeric character:

In [253]: p.add_argument('-3','--third');
In [254]: p.parse_args(['2'])
Out[254]: Namespace(foo=2, third=None)

That disables the use of negative numbers:

In [255]: p.parse_args(['-2'])
usage: ipython3 [-h] [-3 THIRD] foo
ipython3: error: the following arguments are required: foo

In [257]: p.parse_args('-3 xxx 3'.split())
Out[257]: Namespace(foo=3, third='xxx')

In [260]: p.parse_args('-3 -1 3'.split())
usage: ipython3 [-h] [-3 THIRD] foo
ipython3: error: argument -3/--third: expected one argument

According to gnu-unix/linux the pattern you want is obsolete

https://www.gnu.org/software/coreutils/manual/html_node/head-invocation.html

Normally lines are specified with:

‘-n [-]num’

where the negative value counts from the end (as a negative slicing does in Python).

For compatibility head also supports an obsolete option syntax -[num][bkm][cqv]

Early versions of utilities like this parsed the command line values directly (in C code) with whatever syntax the writer thought convenient (as much from a coding standpoint as final usage). You too can do that as indicated in the other answer. But as the systems matured developers used parsers like getopt, and tried to standardize usage.
https://www.gnu.org/software/coreutils/manual/html_node/Common-options.html#Common-options

Generally argparse builds on POSIX standards as inherited via the getopt and optparse modules.

Upvotes: 0

loa_in_
loa_in_

Reputation: 1011

argparse doesn't support dynamic option names.

Source: I tried to do the same thing you ask.

You can accomplish the task itself, but it would have to run either before or after argparse and it would have to modify sys.argv. That makes it so half of the solution will be side-stepping argparse. I recommend you try to find a library that supports this style of parameter passing.

Upvotes: 4

Related Questions