Python Argparse: Default Value or Specified Value

Python argparse: default value or specified value

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--example', nargs='?', const=1, type=int)
args = parser.parse_args()
print(args)

% test.py 
Namespace(example=None)
% test.py --example
Namespace(example=1)
% test.py --example 2
Namespace(example=2)

  • nargs='?' means 0-or-1 arguments
  • const=1 sets the default when there are 0 arguments
  • type=int converts the argument to int

If you want test.py to set example to 1 even if no --example is specified, then include default=1. That is, with

parser.add_argument('--example', nargs='?', const=1, type=int, default=1)

then

% test.py 
Namespace(example=1)

Why does argparse include default value for optional argument even when argument is specified?

The logic for handling defaults is to insert all defaults into the namespace at the start of parsing. Then let parsing replace them. Then at the end of parsing there's a complicated piece of logic:

for each value in the namespace
if it is a string and equals the default
evaluate the string (with `type`) and put it back

For ordinary store actions this works fine, and lets you provide defaults as strings or any value of your choice.

With append this produces your unexpected value. It puts the ['all'] on the namespace, and then appends the new values to that. Since your nargs is '+', it appends a list, resulting in that mix of string and lists.

The append action cannot tell whether it is appending the new value to a list provided by default or a list that's the result of several previous appends. With a None default it will create an empty list, and append to that.

While this doesn't perform as you expected, it actually gives you a lot of control.

The simplest way around this is to leave the default as None. After parsing, just check if this attribute is None, and if so, replace it with your ['all']. It is not evil or contrary to the design intentions of argparse developers. Somethings are easier after all the input has been parsed.

The issue has been raised on Python bug/issues, http://bugs.python.org/issue16399, and probably here on SO before. But I suspect the best a patch can do is to add a note to the documentation, similar to this one from optparse:

"The append action calls the append method on the current value of the option. This means that any default value specified must have an append method. It also means that if the default value is non-empty, the default elements will be present in the parsed value for the option, with any values from the command line appended after those default values".

See the bug/issue for ideas about writing your own append Action subclass.

Python argparse default string value

You can use nargs='?' for this:

parser.add_argument('-o', '--output', 
nargs='?', default=None, const='my_default_location')

If not present, it will produce the default value, if present but without a value it'll use const, otherwise it'll use the supplied value.

Also read through the other examples in the docs, there's a sample for an optional output file which could be useful.

Use an ArgumentParser argument as a default value of another argument

parse_known_args parse the argument and send it to another argument.

pin_file_path= None
parser = ArgumentParser(formatter_class=ArgumentDefaultsHelpFormater)
parser.add_argument('-p', '--pin_file_path', help = "the directory of the given pin file", default = os.getcwd())
args, remaining = parser.parse_known_args()
parser.add_argument('--option2', default=args.pin_file_path)
args = parser.parse_args()

How to differentiate between default value and user given value in argparse, python?

if a user didn't input any value to the optional argument, I want to take the value from previous usage (if any). So, I want to determine whether the value came as a default value or user given value.

Then you don't want to supply a default value; make the parameter optional (e.g. Argparse optional positional arguments? ), and then explicitly check for its presence or absence in the resulting Namespace object and do the appropriate thing in your code logic - presumably, check for a value in previous usage and then supply a default as a last resort. (Think of default values as a shortcut logic to handle the absence of the value; you need more complicated logic, so better to replace that system than to try to work around it.)

Argparse: Way to include default values in '--help'?

Use the argparse.ArgumentDefaultsHelpFormatter formatter:

parser = argparse.ArgumentParser(
# ... other options ...
formatter_class=argparse.ArgumentDefaultsHelpFormatter)

To quote the documentation:

The other formatter class available, ArgumentDefaultsHelpFormatter, will add information about the default value of each of the arguments.

Note that this only applies to arguments that have help text defined; with no help value for an argument, there is no help message to add information about the default value to.

The exact output for your scan-time option then becomes:

  --scan-time [SCAN_TIME]
Wait SCAN-TIME seconds between status checks.
(default: 5)

Argparse append action with default value only if argument doesn't appear

There's a bug/issue discussing this behavior. I wrote several posts to that.

https://bugs.python.org/issue16399 argparse: append action with default list adds to list instead of overriding

For now the only change is in documentation, not in behavior.

All defaults are placed in the namespace at the start of parsing. For ordinary actions, user values overwrite the default. But in the append case, they are just added to what's there already. It doesn't try to distinguish between values placed by the default, and previous user values.

I think the simplest solution is to leave the default as is, and check after parsing for None or empty list (I don't recall which), and insert your default. You don't get extra points for doing all the parsing in argparse. A bit of post parsing processing is quite ok.



Related Topics



Leave a reply



Submit