How to find out if argparse argument has been actually specified on command line?
You can use custom action to tell if an arg value was defaulted or set on command line:
import argparse
class FooAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)
setattr(namespace, self.dest+'_nondefault', True)
parser = argparse.ArgumentParser()
parser.add_argument('--test0', default='meaningful_default', action=FooAction)
parser.add_argument('--test1', default='meaningful_default', action=FooAction)
args = parser.parse_args('--test0 2'.split())
if hasattr(args, 'test0_nondefault'):
print('argument test0 set on command line')
else:
print('default value of test0 is used')
if hasattr(args, 'test1_nondefault'):
print('argument test1 set on command line')
else:
print('default value of test1 is used')
You can use combinations of "const" and "default" to emulate what you want. "nargs" has to be '?'
in this case. For example:
args_group.add_argument('--abc',
metavar='',
nargs='?',
action='store',
const='github.com',
default='',
help='blabla [ default: %(const)s ]')
Then abc
's value will be as follows given different command line arguments.
abc not in command line:
abc =
--abc
:
abc = github.com
--abc stackoverflow.com
:
abc = stackoverflow.com
So you will know abc
doesn't appear in command line when it's blank, for example:
if not args.abc:
# to something
If you prefer to use argparse and to be able to specify default values, there is a simple solution using two parsers.
I. Define your main parser and parse all your arguments with proper defaults:
parser = argparse.ArgumentParser()
parser.add_argument('--test1', default='meaningful_default1')
parser.add_argument('--test2', default='meaningful_default2')
...
args, unparsed = parser.parse_known_args()
II. Define an aux parser with argument_default=argparse.SUPPRESS
to exclude unspecified arguments. Add all the arguments from the main parser but without any defaults:
aux_parser = argparse.ArgumentParser(argument_default=argparse.SUPPRESS)
for arg in vars(args): aux_parser.add_argument('--'+arg)
cli_args, _ = aux_parser.parse_known_args()
This is not an extremely elegant solution, but works well with argparse and all its benefits.
The parser
maintains a seen_actions
set object while parsing (in the _parse_known_args
method). At the end of parsing it checks this set against the required arguments (ones with required=True
), and may issue a error. A variation is also used with mutually exclusive groups.
But this variable is not available outside of that function. So short of some sort of 'hook' that lets you apply your own tests within the parse_args
action, your best option is to test defaults. Or you can look at sys.argv[1:]
.
The default default
is None
. That is nice for this purpose because your user cannot give this value. That is, there's no string that converts to None
(at least not in any of the normal type
methods).
parser.add_argument('--foo') # default=None
...
if args.foo is None:
# clearly foo has not been specified.
args.foo = 'the real default'
else:
# foo was specified
pass