Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the inferred name of variables in argparse in conflicting cases

I have noticed that argparse uses a rather "mystic" way of creating the variables in the parser. I know that the names of the variables are usually easy to infer: it's the stripped version of long or short option (without the -- or - respectively).

Also all hyphens (-) becomes underscores (_) to become legal variable names.

But that leaves me with a question about conflicting cases (I know it's an extreme case but the inferring part it's a bit mysterious to me). For example the program:

import argparse
parser = argparse.ArgumentParser(description="A simple test about var names")
parser.add_argument("--max-value", type=int, help="the maximum value", metavar="Maximum-value")
parser.add_argument("-m", "--max_value", action="store_true", help="Whether to the use maximum value", dest="max1")
args = parser.parse_args()
print("max_value {}".format(args.max1))
print("max-value {}".format(args.max_value))

uses apparently two very similar options (--max-value and --max_value) which lead to the same inferred variable max_value. If either of the options was missing the variable would be max_value without ambiguity.

But when both are present, apparently --max_value gets the trophy variable max_value and the second one (--max-value) gets what? I haven't been able to find what's the second variable.

So, to access it I must define a variable explicitly with dest option? How do I get list of the names of variables available? The funny thing is that if I use dest= for the --max_value option then --max-value gets the expected variable max_value while --max_value gets the non inferred one (in my case max1)!

I know also that metavar has nothing to do with the actual variable name but only affects the display in help.

Edit:

Adding some information from the @Martijn Pieters answer:

If I am getting it write if no dest is applied the parser follows the general rule which states that an implicit dest is applied. The same in my case dest="max_value".

So,

parser.add_argument("--max-value", type=int, help="the maximum value")

is exactly the same as:

parser.add_argument("--max-value", type=int, help="the maximum value", dest="max_value")

internally.

But, then the following code snippets should produce different results which it does not:

# parserv1.py
import argparse
parser = argparse.ArgumentParser(description="A simple test about var names")
parser.add_argument("-m", "--max_value", action="store_true", help="Whether to the use maximum value", dest="max_value")
parser.add_argument("--max-value", type=int, help="the maximum value", metavar="Maximum-value", dest="max_value")
args = parser.parse_args()
print("max-value {}".format(args.max_value))

>>>python parserv1.py -m --max-value 3

max-value 3

# parserv2.py
import argparse
parser = argparse.ArgumentParser(description="A simple test about var names")
parser.add_argument("--max-value", type=int, help="the maximum value", metavar="Maximum-value", dest="max_value")
parser.add_argument("-m", "--max_value", action="store_true", help="Whether to the use maximum value", dest="max_value")
args = parser.parse_args()
print("max-value {}".format(args.max_value))

>>>python parserv1.py -m --max-value 3

max-value 3

Both just print the value of max_value as int independently of the order they are declared.

So, int option have higher precedence than binary (i.e. flags)? Are option types important in these cases?

P.S. I am using python 3.6.3 and since it might be a version issue I wanted to mention it.

like image 381
Eypros Avatar asked Nov 20 '17 10:11

Eypros


People also ask

How do you add arguments in Argparse?

After importing the library, argparse. ArgumentParser() initializes the parser so that you can start to add custom arguments. To add your arguments, use parser. add_argument() .

What does DEST mean in Argparse?

dest is equal to the first argument supplied to the add_argument() function, as illustrated. The second argument, radius_circle , is optional. A long option string --radius supplied to the add_argument() function is used as dest , as illustrated.

What does Nargs do in Argparse?

Number of Arguments If you want your parameters to accept a list of items you can specify nargs=n for how many arguments to accept. Note, if you set nargs=1 , it will return as a list not a single value.

What is ArgumentParser in Python?

Using argparse is how you let the user of your program provide values for variables at runtime. It's a means of communication between the writer of a program and the user. That user might be your future self. 😃 Using argparse means the doesn't need to go into the code and make changes to the script.


1 Answers

There is no conflict here; for both --max-value and --max_value, the library simply generates the exact same destination name. Multiple options writing to the same dest destination name is perfectly valid; the last option used on the command line wins in that case:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument("--option1", dest="foo")
_StoreAction(option_strings=['--option1'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.add_argument("--option2", dest="foo")
_StoreAction(option_strings=['--option2'], dest='foo', nargs=None, const=None, default=None, type=None, choices=None, help=None, metavar=None)
>>> parser.parse_args(['--option2', 'bar', '--option1', 'baz'])
Namespace(foo='baz')

Here --option1 baz wins because --option1 was used last on the command line.

Note that any defaults are applied before command-line parsing; the first registered option default value wins. Then the command-line is parsed and if only one of the options is used, then naturally the action associated with that option wins.

It is up to you to pick non-conflicting destination names. Not picking option strings that are easy to confuse is also a good idea.

If you were looking for a formal set of rules on what dest name is generated for a given optional argument, see the dest option documenation:

For optional argument actions, the value of dest is normally inferred from the option strings. ArgumentParser generates the value of dest by taking the first long option string and stripping away the initial -- string. If no long option strings were supplied, dest will be derived from the first short option string by stripping the initial - character. Any internal - characters will be converted to _ characters to make sure the string is a valid attribute name.


Multiple options all writing to the same dest destination name is useful for supporting old, deprecated names for a given option:

parser.add_argument('-n', '--new', dest='new', help="New hotness option")
# old name for the new hotness option, now deprecated but still supported
# argparse.SUPPRESS ensures it is no longer listed in the help output
parser.add_argument('-o', '--old', dest='new', help=argparse.SUPPRESS)

So using -o or --old on the command line has the exact same effect as using -n or --new; the same destination name is set on the namespace.

like image 60
Martijn Pieters Avatar answered Nov 15 '22 22:11

Martijn Pieters